From patchwork Mon May 18 11:49:17 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dodji Seketeli X-Patchwork-Id: 39286 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 684D6388A825; Mon, 18 May 2020 11:49:23 +0000 (GMT) X-Original-To: libabigail@sourceware.org Delivered-To: libabigail@sourceware.org Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by sourceware.org (Postfix) with ESMTPS id 244D9388A823 for ; Mon, 18 May 2020 11:49:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 244D9388A823 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=seketeli.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=dodji@seketeli.org X-Originating-IP: 91.166.131.130 Received: from localhost (91-166-131-130.subs.proxad.net [91.166.131.130]) (Authenticated sender: dodj@seketeli.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id A8E61FF805 for ; Mon, 18 May 2020 11:49:18 +0000 (UTC) Received: by localhost (Postfix, from userid 1001) id A2CA41A033D; Mon, 18 May 2020 13:49:17 +0200 (CEST) From: Dodji Seketeli To: libabigail@sourceware.org Subject: [PATCH 1/3] {default, leaf}-reporter: group data members changes reports together Organization: Me, myself and I References: <86mu65a2i2.fsf@seketeli.org> X-Operating-System: Red Hat Enterprise Linux Server 7.7 X-URL: http://www.seketeli.net/~dodji X-Patchwork-State: Committed Date: Mon, 18 May 2020 13:49:17 +0200 In-Reply-To: <86mu65a2i2.fsf@seketeli.org> (Dodji Seketeli's message of "Mon, 18 May 2020 13:47:33 +0200") Message-ID: <86imgta2f6.fsf@seketeli.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3 (gnu/linux) MIME-Version: 1.0 X-Spam-Status: No, score=-8.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, JMQ_SPF_NEUTRAL, KAM_DMARC_STATUS, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libabigail@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list of the Libabigail project List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , Errors-To: libabigail-bounces@sourceware.org Sender: "Libabigail" Hello, There are two kinds of data member changes: 1/ changes to the type or offset of a given data member basically, in this kind of change, the name of the data member remained the same. 2/ changes where the data member (at a given offset) was replaced by something else completely. Today, the comparison engine recognizes these two kinds of changes and records them in two different data structures. This is useful because it allows for a finer grain analysis. But when we report these changes, today, we report them separately and sometimes that doesn't make sense. For instance, because there is no change of the 1/ kind, the reporter would say "no data member changes", and yet go ahead and emit data member changes of the 2/ kind. This patch groups the reporting of the two kinds of changes so that when it says "no data member changes", it means there was no data member changes at all. * include/abg-comparison.h (class_or_union_diff::{sorted_changed_data_members, count_filtered_changed_data_members, sorted_subtype_changed_data_members, count_filtered_subtype_changed_data_members}): Declare ... * src/abg-comparison.cc (class_or_union_diff::{sorted_changed_data_members, count_filtered_changed_data_members, sorted_subtype_changed_data_members, count_filtered_subtype_changed_data_members}): ... accessors for existing private data members. * src/abg-default-reporter.cc (default_reporter::report): In the class_or_union_diff& overload, group the reporting of the changes to data member sub-types with the replacement of data members. These are just data member changes after all. Use the newly declared accessors for better measure. * src/abg-leaf-reporter.cc (leaf_reporter::report): Likewise. * tests/data/test-diff-dwarf/test45-anon-dm-change-report-0.txt: Adjust. * src/abg-leaf-reporter.cc (leaf_reporter::report): Likewise. * tests/data/test-diff-pkg/spice-server-0.12.4-19.el7.x86_64-0.12.8-1.el7.x86_64-report-2.txt: Likewise. Signed-off-by: Dodji Seketeli Applied to master. --- include/abg-comparison.h | 12 +++++ src/abg-comparison.cc | 30 ++++++++++++ src/abg-default-reporter.cc | 51 ++++++++------------ src/abg-leaf-reporter.cc | 55 ++++++---------------- .../test45-anon-dm-change-report-0.txt | 5 +- ...-19.el7.x86_64-0.12.8-1.el7.x86_64-report-2.txt | 9 ++-- 6 files changed, 82 insertions(+), 80 deletions(-) diff --git a/include/abg-comparison.h b/include/abg-comparison.h index 4f60ff9..cf95624 100644 --- a/include/abg-comparison.h +++ b/include/abg-comparison.h @@ -1598,6 +1598,18 @@ public: const string_member_function_sptr_map& inserted_member_fns() const; + const var_diff_sptrs_type& + sorted_changed_data_members() const; + + size_t + count_filtered_changed_data_members(bool local_only = false) const; + + const var_diff_sptrs_type& + sorted_subtype_changed_data_members() const; + + size_t + count_filtered_subtype_changed_data_members(bool local_only = false) const; + const edit_script& member_fn_tmpls_changes() const; diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc index 57cc6c2..e4a983b 100644 --- a/src/abg-comparison.cc +++ b/src/abg-comparison.cc @@ -4955,6 +4955,36 @@ const string_member_function_sptr_map& class_or_union_diff::inserted_member_fns() const {return get_priv()->inserted_member_functions_;} +/// Getter of the sorted vector of data members that got replaced by +/// another data member. +/// +/// @return sorted vector of changed data member. +const var_diff_sptrs_type& +class_or_union_diff::sorted_changed_data_members() const +{return get_priv()->sorted_changed_dm_;} + +/// Count the number of /filtered/ data members that got replaced by +/// another data member. +/// +/// @return the number of changed data member that got filtered out. +size_t +class_or_union_diff::count_filtered_changed_data_members(bool local) const +{return get_priv()->count_filtered_changed_dm(local);} + +/// Getter of the sorted vector of data members with a (sub-)type change. +/// +/// @return sorted vector of changed data member. +const var_diff_sptrs_type& +class_or_union_diff::sorted_subtype_changed_data_members() const +{return get_priv()->sorted_subtype_changed_dm_;} + +/// Count the number of /filtered/ data members with a sub-type change. +/// +/// @return the number of changed data member that got filtered out. +size_t +class_or_union_diff::count_filtered_subtype_changed_data_members(bool local) const +{return get_priv()->count_filtered_subtype_changed_dm(local);} + /// @return the edit script of the member function templates of the two /// @ref class_or_union. const edit_script& diff --git a/src/abg-default-reporter.cc b/src/abg-default-reporter.cc index 5892bec..b59e8d6 100644 --- a/src/abg-default-reporter.cc +++ b/src/abg-default-reporter.cc @@ -989,43 +989,32 @@ default_reporter::report(const class_or_union_diff& d, } // report change - size_t numchanges = - d.class_or_union_diff::get_priv()->sorted_subtype_changed_dm_.size(); - size_t num_filtered = - d.class_or_union_diff::get_priv()->count_filtered_subtype_changed_dm(); - if (numchanges) + size_t num_changes = + (d.sorted_subtype_changed_data_members().size() + + d.sorted_changed_data_members().size()); + + size_t num_changes_filtered = + (d.count_filtered_subtype_changed_data_members() + + d.count_filtered_changed_data_members()); + + if (num_changes) { - report_mem_header(out, numchanges, num_filtered, - subtype_change_kind, "data member", indent); + report_mem_header(out, num_changes, num_changes_filtered, + change_kind, "data member", indent); + for (var_diff_sptrs_type::const_iterator it = - d.class_or_union_diff::get_priv()->sorted_subtype_changed_dm_.begin(); - it != d.class_or_union_diff::get_priv()->sorted_subtype_changed_dm_.end(); + d.sorted_changed_data_members().begin(); + it != d.sorted_changed_data_members().end(); ++it) - { - if ((*it)->to_be_reported()) - { - represent(*it, ctxt, out, indent + " "); - } - } - } + if ((*it)->to_be_reported()) + represent(*it, ctxt, out, indent + " "); - numchanges = d.class_or_union_diff::get_priv()->sorted_changed_dm_.size(); - num_filtered = - d.class_or_union_diff::get_priv()->count_filtered_changed_dm(); - if (numchanges) - { - report_mem_header(out, numchanges, num_filtered, - change_kind, "data member", indent); for (var_diff_sptrs_type::const_iterator it = - d.class_or_union_diff::get_priv()->sorted_changed_dm_.begin(); - it != d.class_or_union_diff::get_priv()->sorted_changed_dm_.end(); + d.sorted_subtype_changed_data_members().begin(); + it != d.sorted_subtype_changed_data_members().end(); ++it) - { - if ((*it)->to_be_reported()) - { - represent(*it, ctxt, out, indent + " "); - } - } + if ((*it)->to_be_reported()) + represent(*it, ctxt, out, indent + " "); } } diff --git a/src/abg-leaf-reporter.cc b/src/abg-leaf-reporter.cc index 16e8f36..afe5692 100644 --- a/src/abg-leaf-reporter.cc +++ b/src/abg-leaf-reporter.cc @@ -603,58 +603,33 @@ leaf_reporter::report(const class_or_union_diff& d, } // report changes - size_t numchanges = - d.class_or_union_diff::get_priv()->sorted_changed_dm_.size(); + size_t numchanges = (d.sorted_changed_data_members().size() + + d.sorted_subtype_changed_data_members().size()); + size_t num_filtered = - d.class_or_union_diff::get_priv()-> - count_filtered_changed_dm(/*local_only =*/ true); + (d.count_filtered_changed_data_members(/*local_only=*/true) + + d.count_filtered_subtype_changed_data_members(/*local_only=*/true)); + ABG_ASSERT(numchanges >= num_filtered); size_t net_numchanges = numchanges - num_filtered; - bool emitted_data_members_changes = false; if (net_numchanges) { report_mem_header(out, change_kind, "data member", indent); + for (var_diff_sptrs_type::const_iterator it = - d.class_or_union_diff::get_priv()-> - sorted_changed_dm_.begin(); - it != d.class_or_union_diff::get_priv()-> - sorted_changed_dm_.end(); + d.sorted_changed_data_members().begin(); + it != d.sorted_changed_data_members().end(); ++it) - { - if (diff_to_be_reported((*it).get())) - { - represent(*it, ctxt, out, indent + " ", - /*local_only=*/true); - emitted_data_members_changes = true; - } - } - } + if (diff_to_be_reported((*it).get())) + represent(*it, ctxt, out, indent + " ", /*local_only=*/true); - numchanges = - d.class_or_union_diff::get_priv()->sorted_subtype_changed_dm_.size(); - num_filtered = - d.class_or_union_diff::get_priv()-> - count_filtered_subtype_changed_dm(/*local_only =*/ true); - ABG_ASSERT(numchanges >= num_filtered); - net_numchanges = numchanges - num_filtered; - - if (net_numchanges) - { - if (!emitted_data_members_changes) - report_mem_header(out, subtype_change_kind, "data member", indent); for (var_diff_sptrs_type::const_iterator it = - d.class_or_union_diff::get_priv()->sorted_subtype_changed_dm_.begin(); - it != d.class_or_union_diff::get_priv()->sorted_subtype_changed_dm_.end(); + d.sorted_subtype_changed_data_members().begin(); + it != d.sorted_subtype_changed_data_members().end(); ++it) - { - if (diff_to_be_reported((*it).get())) - { - represent(*it, ctxt, out, indent + " ", - /*local_only=*/true); - emitted_data_members_changes = true; - } - } + if (diff_to_be_reported((*it).get())) + represent(*it, ctxt, out, indent + " ", /*local_only=*/true); } } } diff --git a/tests/data/test-diff-dwarf/test45-anon-dm-change-report-0.txt b/tests/data/test-diff-dwarf/test45-anon-dm-change-report-0.txt index 2f8f31d..4ffd8b3 100644 --- a/tests/data/test-diff-dwarf/test45-anon-dm-change-report-0.txt +++ b/tests/data/test-diff-dwarf/test45-anon-dm-change-report-0.txt @@ -9,11 +9,10 @@ Variables changes summary: 0 Removed, 0 Changed, 0 Added variable type size changed from 96 to 64 (in bits) 1 data member insertion: 'char S1::m01', at offset 32 (in bits) - 1 data member change: - 'char S1::m1' offset changed from 64 to 40 (in bits) (by -24 bits) - 1 data member change: + 2 data member changes: anonymous data member struct {int m0; char m01;} at offset 0 (in bits) became data member 'int S1::m0' and size changed from 64 to 32 (in bits) (by -32 bits) + 'char S1::m1' offset changed from 64 to 40 (in bits) (by -24 bits) [C] 'function void foo(S0&)' has some indirect sub-type changes: parameter 1 of type 'S0&' has sub-type changes: diff --git a/tests/data/test-diff-pkg/spice-server-0.12.4-19.el7.x86_64-0.12.8-1.el7.x86_64-report-2.txt b/tests/data/test-diff-pkg/spice-server-0.12.4-19.el7.x86_64-0.12.8-1.el7.x86_64-report-2.txt index 58c94b7..c64da3b 100644 --- a/tests/data/test-diff-pkg/spice-server-0.12.4-19.el7.x86_64-0.12.8-1.el7.x86_64-report-2.txt +++ b/tests/data/test-diff-pkg/spice-server-0.12.4-19.el7.x86_64-0.12.8-1.el7.x86_64-report-2.txt @@ -159,11 +159,11 @@ in pointed to type 'typedef SpiceServer' at spice-server.h:38:1: underlying type 'struct RedsState' at reds-private.h:127:1 changed: type size hasn't changed - 2 data member changes (1 filtered): + 2 data member changes (2 filtered): type of 'VDIPortState RedsState::agent_state' changed: underlying type 'struct VDIPortState' at reds-private.h:46:1 changed: type size hasn't changed - 1 data member change: + 1 data member changes (3 filtered): type of 'SpiceCharDeviceState* VDIPortState::base' changed: in pointed to type 'typedef SpiceCharDeviceState' at spice-char.h:34:1: underlying type 'struct SpiceCharDeviceState' at char_device.c:47:1 changed: @@ -199,7 +199,6 @@ pointed to type 'typedef SpiceCharDeviceInstance' changed at spice.h:399:1, as reported earlier and offset changed from 1024 to 1088 (in bits) (by +64 bits) 'void* SpiceCharDeviceState::opaque' offset changed from 1472 to 1536 (in bits) (by +64 bits) - no data member changes (3 filtered); type of 'MainChannel* RedsState::main_channel' changed: in pointed to type 'typedef MainChannel' at main_channel.h:48:1: underlying type 'struct MainChannel' at main_channel.h:36:1 changed: @@ -404,7 +403,6 @@ in pointed to type 'function type void (RedChannelClient*)': parameter 1 of type 'RedChannelClient*' has sub-type changes: pointed to type 'typedef RedChannelClient' changed at red_channel.h:136:1, as reported earlier - no data member change (1 filtered); [C] 'function int spice_server_add_interface(SpiceServer*, SpiceBaseInstance*)' at reds.c:3159:1 has some indirect sub-type changes: parameter 1 of type 'SpiceServer*' has sub-type changes: @@ -519,7 +517,7 @@ in pointed to type 'typedef SndChannel' at snd_worker.c:74:1: underlying type 'struct SndChannel' at snd_worker.c:89:1 changed: type size hasn't changed - 6 data member changes: + 6 data member changes (1 filtered): type of 'RedsStream* SndChannel::stream' changed: pointed to type 'typedef RedsStream' changed at red_channel.h:134:1, as reported earlier type of 'SndWorker* SndChannel::worker' changed: @@ -545,7 +543,6 @@ parameter 1 of type 'SndChannel*' has sub-type changes: in pointed to type 'typedef SndChannel' at snd_worker.c:74:1: underlying type 'struct SndChannel' changed, as being reported - no data member change (1 filtered); type of 'SndWorker* SndWorker::next' changed: in pointed to type 'typedef SndWorker' at snd_worker.c:80:1: underlying type 'struct SndWorker' changed, as being reported From patchwork Mon May 18 11:50:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dodji Seketeli X-Patchwork-Id: 39289 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5A7F4388A825; Mon, 18 May 2020 11:50:52 +0000 (GMT) X-Original-To: libabigail@sourceware.org Delivered-To: libabigail@sourceware.org Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by sourceware.org (Postfix) with ESMTPS id A2F24388A83F for ; Mon, 18 May 2020 11:50:40 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org A2F24388A83F Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=seketeli.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=dodji@seketeli.org X-Originating-IP: 91.166.131.130 Received: from localhost (91-166-131-130.subs.proxad.net [91.166.131.130]) (Authenticated sender: dodj@seketeli.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 703F51BF209 for ; Mon, 18 May 2020 11:50:37 +0000 (UTC) Received: by localhost (Postfix, from userid 1001) id 70BB31A033D; Mon, 18 May 2020 13:50:36 +0200 (CEST) From: Dodji Seketeli To: libabigail@sourceware.org Subject: [PATCH 2/3] dwarf-reader: support several anonymous data members in a given class Organization: Me, myself and I References: <86mu65a2i2.fsf@seketeli.org> X-Operating-System: Red Hat Enterprise Linux Server 7.7 X-URL: http://www.seketeli.net/~dodji X-Patchwork-State: Committed Date: Mon, 18 May 2020 13:50:36 +0200 In-Reply-To: <86mu65a2i2.fsf@seketeli.org> (Dodji Seketeli's message of "Mon, 18 May 2020 13:47:33 +0200") Message-ID: <86eerha2cz.fsf@seketeli.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3 (gnu/linux) MIME-Version: 1.0 X-Spam-Status: No, score=-7.4 required=5.0 tests=BAYES_00, GIT_PATCH_0, JMQ_SPF_NEUTRAL, KAM_ASCII_DIVIDERS, KAM_DMARC_STATUS, RCVD_IN_DNSWL_LOW, SCC_10_SHORT_WORD_LINES, SCC_5_SHORT_WORD_LINES, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libabigail@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list of the Libabigail project List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , Errors-To: libabigail-bounces@sourceware.org Sender: "Libabigail" Hello, At the moment, if a class has more than one anonymous data member, we are just keeping the first one and dropping the others. This patch fixes that. Now that there is the possibility of having several anonymous data members in a given class we need to be able to name them correctly, to tell them apart. That means we cannot use the name returned by var_decl::get_name() as that name is empty for an anonymous data member. This patch thus introduces a new method var_decl::get_anon_dm_reliable_name() which returns a name that is reliable (non-empty) even when the var_decl designates an anonymous data member. Note that there are many situations where we still need to have var_decl::get_name() behave like it used to, so we can't make it invariably return what var_decl::get_anon_dm_reliable_name() returns today. * include/abg-ir.h (class_or_union::find_anonymous_data_member): Declare a new member function. (class_or_union::find_data_member): Declare a new overload. (var_decl::get_anon_dm_reliable_name): Declare new member function. * src/abg-ir.cc (var_decl::get_pretty_representation): Make this work on a var_decl is going to be used to represent an anonymous data member even before the var_decl has been added to its finale scope. This is useful to make class_or_union::find_data_member work on a var_decl that is to be used as an anonymous data member. (var_decl::get_anon_dm_reliable_name): Define new member function. (class_or_union::find_data_member): In the existing overload that takes a string, look for the named data member inside the anonymous data members. Define a new overload that takes a var_decl_sptr, to look for anonymous data members. (class_or_union::find_anonymous_data_member): Define a new member function. (lookup_data_member): Use the existing class_or_union::find_data_member. * src/abg-reader.cc: (build_class_decl): Use the full anonymous variable for lookup, rather than its name which is empty and will thus give false positives. * src/abg-dwarf-reader.cc (add_or_update_class_type): Likewise. * src/abg-comparison.cc (class_or_union_diff::ensure_lookup_tables_populated): Name anonymous data members properly - as opposed to wrongly using their empty name. * src/abg-reporter-priv.cc (represent): In the overload for var_diff_sptr, make sure that changes to the /type/ of a variable declaration are always reported. * tests/data/test-abidiff-exit/test-member-size-report0.txt: Adjust as we now emit more detailed changes about anonymous data members. * tests/data/test-abidiff-exit/test-member-size-report1.txt: Likewise. * tests/data/test-annotate/test-anonymous-members-0.o.abi: Adjust to reflect the fact that a class can now have several anonymous data members. * tests/data/test-diff-dwarf-abixml/PR25409-librte_bus_dpaa.so.20.0.abi: Likewise. * tests/data/test-diff-filter/test30-pr18904-rvalueref-report0.txt: Likewise. * tests/data/test-diff-filter/test30-pr18904-rvalueref-report1.txt: Likewise. * tests/data/test-diff-filter/test35-pr18754-no-added-syms-report-0.txt: Likewise. Signed-off-by: Dodji Seketeli Applied to master. --- include/abg-ir.h | 9 + src/abg-comparison.cc | 20 +- src/abg-dwarf-reader.cc | 15 +- src/abg-ir.cc | 103 +++- src/abg-reader.cc | 2 +- src/abg-reporter-priv.cc | 84 ++- .../test-abidiff-exit/test-member-size-report0.txt | 5 +- .../test-abidiff-exit/test-member-size-report1.txt | 5 +- .../test-annotate/test-anonymous-members-0.o.abi | 16 + .../PR25409-librte_bus_dpaa.so.20.0.abi | 656 ++++++++++----------- .../test30-pr18904-rvalueref-report0.txt | 2 +- .../test30-pr18904-rvalueref-report1.txt | 2 +- .../test30-pr18904-rvalueref-report2.txt | 2 +- .../test35-pr18754-no-added-syms-report-0.txt | 2 +- 14 files changed, 539 insertions(+), 384 deletions(-) diff --git a/include/abg-ir.h b/include/abg-ir.h index 97648c0..15b0b40 100644 --- a/include/abg-ir.h +++ b/include/abg-ir.h @@ -2766,6 +2766,9 @@ public: get_pretty_representation(bool internal = false, bool qualified_name = true) const; + string + get_anon_dm_reliable_name(bool qualified = true) const; + virtual bool traverse(ir_node_visitor& v); @@ -3832,6 +3835,12 @@ public: const var_decl_sptr find_data_member(const string&) const; + const var_decl_sptr + find_data_member(const var_decl_sptr&) const; + + const var_decl_sptr + find_anonymous_data_member(const var_decl_sptr&) const; + const data_members& get_non_static_data_members() const; diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc index e4a983b..e1689e5 100644 --- a/src/abg-comparison.cc +++ b/src/abg-comparison.cc @@ -4664,11 +4664,13 @@ class_or_union_diff::ensure_lookup_tables_populated(void) const ++it) { unsigned i = it->index(); - decl_base_sptr d = first_class_or_union()->get_non_static_data_members()[i]; - string name = d->get_name(); + var_decl_sptr data_member = + is_var_decl(first_class_or_union()->get_non_static_data_members()[i]); + string name = data_member->get_anon_dm_reliable_name(); + ABG_ASSERT(priv_->deleted_data_members_.find(name) - == priv_->deleted_data_members_.end()); - priv_->deleted_data_members_[name] = d; + == priv_->deleted_data_members_.end()); + priv_->deleted_data_members_[name] = data_member; } for (vector::const_iterator it = e.insertions().begin(); @@ -4683,8 +4685,8 @@ class_or_union_diff::ensure_lookup_tables_populated(void) const unsigned i = *iit; decl_base_sptr d = second_class_or_union()->get_non_static_data_members()[i]; - var_decl_sptr dm = is_var_decl(d); - string name = dm->get_name(); + var_decl_sptr added_dm = is_var_decl(d); + string name = added_dm->get_anon_dm_reliable_name(); ABG_ASSERT(priv_->inserted_data_members_.find(name) == priv_->inserted_data_members_.end()); string_decl_base_sptr_map::const_iterator j = @@ -4695,7 +4697,7 @@ class_or_union_diff::ensure_lookup_tables_populated(void) const { var_decl_sptr old_dm = is_var_decl(j->second); priv_->subtype_changed_dm_[name]= - compute_diff(old_dm, dm, context()); + compute_diff(old_dm, added_dm, context()); } priv_->deleted_data_members_.erase(j); } @@ -4749,9 +4751,9 @@ class_or_union_diff::ensure_lookup_tables_populated(void) const priv_->deleted_dm_by_offset_.erase(i->first); priv_->inserted_dm_by_offset_.erase(i->first); priv_->deleted_data_members_.erase - (i->second->first_var()->get_name()); + (i->second->first_var()->get_anon_dm_reliable_name()); priv_->inserted_data_members_.erase - (i->second->second_var()->get_name()); + (i->second->second_var()->get_anon_dm_reliable_name()); } } sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_, diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc index 4bcc652..77af044 100644 --- a/src/abg-dwarf-reader.cc +++ b/src/abg-dwarf-reader.cc @@ -13995,8 +13995,9 @@ add_or_update_class_type(read_context& ctxt, continue; // If the variable is already a member of this class, - // move on. - if (lookup_var_decl_in_scope(n, result)) + // move on. If it's an anonymous data member, we need + // to handle it differently. We'll do that later below. + if (!n.empty() && lookup_var_decl_in_scope(n, result)) continue; int64_t offset_in_bits = 0; @@ -14023,8 +14024,10 @@ add_or_update_class_type(read_context& ctxt, // The call to build_ir_node_from_die above could have // triggered the adding of a data member named 'n' into // result. So let's check again if the variable is - // already a member of this class. - if (lookup_var_decl_in_scope(n, result)) + // already a member of this class. Here again, if it's + // an anonymous data member, we need to handle it + // differently. We'll do that later below. + if (!n.empty() && lookup_var_decl_in_scope(n, result)) continue; if (!is_static) @@ -14040,6 +14043,10 @@ add_or_update_class_type(read_context& ctxt, die_access_specifier(&child, access); var_decl_sptr dm(new var_decl(n, t, loc, m)); + if (n.empty() && result->find_data_member(dm)) + // dm is an anonymous data member that was already + // present in the current class so let's not add it. + continue; result->add_data_member(dm, access, is_laid_out, is_static, offset_in_bits); ABG_ASSERT(has_scope(dm)); diff --git a/src/abg-ir.cc b/src/abg-ir.cc index 7b1f460..85c27e3 100644 --- a/src/abg-ir.cc +++ b/src/abg-ir.cc @@ -15860,7 +15860,9 @@ var_decl::get_pretty_representation(bool internal, bool qualified_name) const } else { - if (is_anonymous_data_member(this)) + if (/*The current var_decl is to be used as an anonymous data + member. */ + get_name().empty()) { // Display the anonymous data member in a way that // makes sense. @@ -15903,6 +15905,30 @@ var_decl::get_pretty_representation(bool internal, bool qualified_name) const return result; } +/// Get a name that is valid even for an anonymous data member. +/// +/// If the current @ref var_decl is an anonymous data member, then +/// return its pretty representation. As of now, that pretty +/// representation is actually its flat representation as returned by +/// get_class_or_union_flat_representation(). +/// +/// Otherwise, just return the name of the current @ref var_decl. +/// +/// @param qualified if true, return the qualified name. This doesn't +/// have an effet if the current @ref var_decl represents an anonymous +/// data member. +string +var_decl::get_anon_dm_reliable_name(bool qualified) const +{ + string name; + if (is_anonymous_data_member(this)) + name = get_pretty_representation(true, qualified); + else + name = get_name(); + + return name; +} + /// This implements the ir_traversable_base::traverse pure virtual /// function. /// @@ -18495,9 +18521,74 @@ class_or_union::find_data_member(const string& name) const ++i) if ((*i)->get_name() == name) return *i; + + // We haven't found a data member with the name 'name'. Let's look + // closer again, this time in our anonymous data members. + for (data_members::const_iterator i = get_data_members().begin(); + i != get_data_members().end(); + ++i) + if (is_anonymous_data_member(*i)) + { + class_or_union_sptr type = is_class_or_union_type((*i)->get_type()); + ABG_ASSERT(type); + if (var_decl_sptr data_member = type->find_data_member(name)) + return data_member; + } + + return var_decl_sptr(); +} + +/// Find an anonymous data member in the class. +/// +/// @param v the anonymous data member to find. +/// +/// @return the anonymous data member found, or nil if none was found. +const var_decl_sptr +class_or_union::find_anonymous_data_member(const var_decl_sptr& v) const +{ + if (!v->get_name().empty()) + return var_decl_sptr(); + + for (data_members::const_iterator it = get_non_static_data_members().begin(); + it != get_non_static_data_members().end(); + ++it) + { + if (is_anonymous_data_member(*it)) + if ((*it)->get_pretty_representation(true, true) + == v->get_pretty_representation(true, true)) + return *it; + } + return var_decl_sptr(); } +/// Find a given data member. +/// +/// This function takes a @ref var_decl as an argument. If it has a +/// non-empty name, then it tries to find a data member which has the +/// same name as the argument. +/// +/// If it has an empty name, then the @ref var_decl is considered as +/// an anonymous data member. In that case, this function tries to +/// find an anonymous data member which type equals that of the @ref +/// var_decl argument. +/// +/// @param v this carries either the name of the data member we need +/// to look for, or the type of the anonymous data member we are +/// looking for. +const var_decl_sptr +class_or_union::find_data_member(const var_decl_sptr& v) const +{ + if (!v) + return var_decl_sptr(); + + if (v->get_name().empty()) + return find_anonymous_data_member(v); + + return find_data_member(v->get_name()); +} + + /// Get the non-static data memebers of this @ref class_or_union. /// /// @return a vector of the non-static data members of this @ref @@ -22800,15 +22891,7 @@ lookup_data_member(const type_base* type, if (!cou) return 0; - for (class_or_union::data_members::const_iterator i = - cou->get_data_members().begin(); - i != cou->get_data_members().end(); - ++i) - { - if ((*i)->get_name() == dm_name) - return i->get(); - } - return 0; + return cou->find_data_member(dm_name).get(); } /// Get the function parameter designated by its index. diff --git a/src/abg-reader.cc b/src/abg-reader.cc index d1bf604..eb74659 100644 --- a/src/abg-reader.cc +++ b/src/abg-reader.cc @@ -4646,7 +4646,7 @@ build_class_decl(read_context& ctxt, if (var_decl_sptr v = build_var_decl(ctxt, p, /*add_to_cur_scope=*/false)) { - if (decl->find_data_member(v->get_name())) + if (decl->find_data_member(v)) { // We are in updating mode and the current // version of this class already has this data diff --git a/src/abg-reporter-priv.cc b/src/abg-reporter-priv.cc index 4ea591a..df7df88 100644 --- a/src/abg-reporter-priv.cc +++ b/src/abg-reporter-priv.cc @@ -432,6 +432,19 @@ represent(const var_diff_sptr &diff, // Have we reported a size change already? bool size_reported = false; + //---------------------------------------------------------------- + // First we'll try to emit a report about the type change of this + // var_decl_diff. + // + // In the context of that type change report, we need to keep in + // mind that because we want to emit specific (useful) reports about + // anonymous data member changes, we'll try to detect the various + // scenarii that involve anonymous data member changes. + // + // Then, as a fallback method, we'll emit a more generic type change + // report for the other generic type changes. + //---------------------------------------------------------------- + if (is_strict_anonymous_data_member_change) { const string n_pretty_representation = n->get_pretty_representation(); @@ -484,34 +497,53 @@ represent(const var_diff_sptr &diff, begin_with_and = true; emitted = true; } - else if (const diff_sptr d = diff->type_diff()) - { - if (ctxt->get_reporter()->diff_to_be_reported(d.get())) - { - if (local_only) - out << indent << "type '" - << get_pretty_representation(o->get_type()) - << "' of '" << o->get_qualified_name() - << "' changed"; - else - out << indent - << "type of '" << o_pretty_representation << "' changed"; - if (d->currently_reporting()) - out << ", as being reported\n"; - else if (d->reported_once()) - out << ", as reported earlier\n"; - else - { - out << ":\n"; - d->report(out, indent + " "); - } + // + // If we haven't succeeded in emitting a specific type change report + // (mainly related to anonymous data data member changes) then let's + // try to emit a more generic report about the type change. + // + // This is the fallback method outlined in the comment at the + // beginning of this section. + // + if (!emitted) + if (const diff_sptr d = diff->type_diff()) + { + if (ctxt->get_reporter()->diff_to_be_reported(d.get())) + { + if (local_only) + out << indent << "type '" + << get_pretty_representation(o->get_type()) + << "' of '" + << (o_anon ? + string("anonymous data member") + : o->get_qualified_name()) + << "' changed"; + else + out << indent + << "type of '"<< (o_anon ? "anonymous data member ": "") + << o_pretty_representation << "' changed"; + + if (d->currently_reporting()) + out << ", as being reported\n"; + else if (d->reported_once()) + out << ", as reported earlier\n"; + else + { + out << ":\n"; + d->report(out, indent + " "); + } + + begin_with_and = true; + emitted = true; + size_reported = true; + } + } - begin_with_and = true; - emitted = true; - size_reported = true; - } - } + // + // Okay, now we are done with report type changes. Let's report the + // other potential kinds of changes. + // if (!filtering::has_anonymous_data_member_change(diff) && o_name != n_name) { diff --git a/tests/data/test-abidiff-exit/test-member-size-report0.txt b/tests/data/test-abidiff-exit/test-member-size-report0.txt index ff93dd5..c82a5c3 100644 --- a/tests/data/test-abidiff-exit/test-member-size-report0.txt +++ b/tests/data/test-abidiff-exit/test-member-size-report0.txt @@ -22,6 +22,9 @@ Variables changes summary: 0 Removed, 0 Changed, 0 Added variable in pointed to type 'struct U' at test-member-size-v1.cc:19:1: type size changed from 192 to 256 (in bits) 2 data member changes: - anonymous data member 'struct {S s;}' size changed from 128 to 192 (in bits) (by +64 bits) + type of 'anonymous data member struct {S s;}' changed: + type size changed from 128 to 192 (in bits) + 1 data member change: + 'S s' size changed from 128 to 192 (in bits) (by +64 bits) 'int U::r' offset changed from 128 to 192 (in bits) (by +64 bits) diff --git a/tests/data/test-abidiff-exit/test-member-size-report1.txt b/tests/data/test-abidiff-exit/test-member-size-report1.txt index dbad76b..7650628 100644 --- a/tests/data/test-abidiff-exit/test-member-size-report1.txt +++ b/tests/data/test-abidiff-exit/test-member-size-report1.txt @@ -17,5 +17,8 @@ Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable 'struct U at test-member-size-v0.cc:18:1' changed: type size changed from 192 to 256 (in bits) there are data member changes: - anonymous data member 'struct {S s;}' size changed from 128 to 192 (in bits) (by +64 bits) + type 'struct {S s;}' of 'anonymous data member' changed: + type size changed from 128 to 192 (in bits) + there are data member changes: + type 'struct S' of 'U::__anonymous_struct__::s' changed, as reported earlier 'int U::r' offset changed from 128 to 192 (in bits) (by +64 bits) diff --git a/tests/data/test-annotate/test-anonymous-members-0.o.abi b/tests/data/test-annotate/test-anonymous-members-0.o.abi index 7334730..83496d0 100644 --- a/tests/data/test-annotate/test-anonymous-members-0.o.abi +++ b/tests/data/test-annotate/test-anonymous-members-0.o.abi @@ -107,6 +107,14 @@ + + + + + + + + @@ -119,6 +127,14 @@ + + + + + + + + diff --git a/tests/data/test-diff-dwarf-abixml/PR25409-librte_bus_dpaa.so.20.0.abi b/tests/data/test-diff-dwarf-abixml/PR25409-librte_bus_dpaa.so.20.0.abi index cd16cc0..7ab00fd 100644 --- a/tests/data/test-diff-dwarf-abixml/PR25409-librte_bus_dpaa.so.20.0.abi +++ b/tests/data/test-diff-dwarf-abixml/PR25409-librte_bus_dpaa.so.20.0.abi @@ -1,4 +1,4 @@ - + @@ -1054,55 +1054,19 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + - + - + @@ -1112,13 +1076,13 @@ - + - + @@ -1141,7 +1105,35 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1149,10 +1141,10 @@ - + - + @@ -1160,6 +1152,14 @@ + + + + + + + + @@ -1243,7 +1243,7 @@ - + @@ -1361,7 +1361,7 @@ - + @@ -1411,33 +1411,8 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + @@ -1445,31 +1420,37 @@ + + + + + + - + - + - + - + @@ -1483,7 +1464,15 @@ - + + + + + + + + + @@ -1491,7 +1480,18 @@ - + + + + + + + + + + + + @@ -1513,7 +1513,7 @@ - + @@ -1625,25 +1625,14 @@ - - - - - - - - - - - - - + + - + - + @@ -1658,7 +1647,7 @@ - + @@ -1666,24 +1655,27 @@ + + + - + - + - + - + - + @@ -1700,15 +1692,15 @@ - + - + - + @@ -1716,12 +1708,20 @@ - + + + + + + + + + - + @@ -1787,7 +1787,7 @@ - + @@ -1814,7 +1814,7 @@ - + @@ -2021,28 +2021,6 @@ - - - - - - - - - - - - - - - - - - - - - - @@ -2053,18 +2031,24 @@ - + + + + + + + - + - + - + @@ -2075,7 +2059,15 @@ - + + + + + + + + + @@ -2086,6 +2078,14 @@ + + + + + + + + @@ -2110,7 +2110,7 @@ - + @@ -2196,7 +2196,7 @@ - + @@ -2221,33 +2221,22 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + + - + - + @@ -2276,74 +2265,36 @@ + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + + + + @@ -2354,7 +2305,10 @@ - + + + + @@ -2365,6 +2319,9 @@ + + + @@ -2375,13 +2332,19 @@ - + + + + - + - + + + + @@ -2393,32 +2356,48 @@ - + - - + + + + + + + + + + + + - + - + - - - - + + - + - - - + + + + + + + + + + + @@ -2432,21 +2411,21 @@ - + - + - + - + @@ -2454,40 +2433,45 @@ - + + + + + + - + - + - + - + - + - + - + - + @@ -2495,7 +2479,7 @@ - + @@ -2509,7 +2493,7 @@ - + @@ -2520,18 +2504,26 @@ - + + + + + + + + + - + - + @@ -2558,25 +2550,25 @@ - + - + - + - + - + @@ -2584,23 +2576,15 @@ - - - - - - - - - - - - + - + + + + @@ -2609,24 +2593,32 @@ - + - + + + + - + + + + + + + - + - - - - + + + @@ -2640,84 +2632,92 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + + + + + + + - + - + - - + @@ -2745,7 +2745,7 @@ - + @@ -2844,8 +2844,8 @@ - - + + @@ -2866,15 +2866,15 @@ - - - - - - - - - + + + + + + + + + @@ -2883,7 +2883,7 @@ - + @@ -3077,8 +3077,8 @@ - - + + @@ -3113,7 +3113,7 @@ - + @@ -3127,7 +3127,7 @@ - + @@ -4648,7 +4648,7 @@ - + @@ -5264,7 +5264,7 @@ - + @@ -5567,7 +5567,7 @@ - + diff --git a/tests/data/test-diff-filter/test30-pr18904-rvalueref-report0.txt b/tests/data/test-diff-filter/test30-pr18904-rvalueref-report0.txt index 79d4191..d30e8c6 100644 --- a/tests/data/test-diff-filter/test30-pr18904-rvalueref-report0.txt +++ b/tests/data/test-diff-filter/test30-pr18904-rvalueref-report0.txt @@ -1298,7 +1298,7 @@ Variable symbols changes summary: 0 Removed, 0 Added variable symbol not referen parameter 1 of type 'VarDesc*' has sub-type changes: in pointed to type 'struct VarDesc': type size hasn't changed - 1 data member changes (1 filtered): + 1 data member changes (2 filtered): type of 'union {struct {uint32_t is_static; uint32_t is_static_dstn; uint32_t has_length; uint32_t is_stack_buf; uint32_t sink_addr; uint32_t alloc_disp; uint32_t is_noncont_src; uint32_t is_noncont_dst;}; uint32_t bits;} VarDesc::flags' changed: type name changed from 'VarDesc::__anonymous_union__2' to 'varDescFlags' type size hasn't changed diff --git a/tests/data/test-diff-filter/test30-pr18904-rvalueref-report1.txt b/tests/data/test-diff-filter/test30-pr18904-rvalueref-report1.txt index 215cfbe..800cc67 100644 --- a/tests/data/test-diff-filter/test30-pr18904-rvalueref-report1.txt +++ b/tests/data/test-diff-filter/test30-pr18904-rvalueref-report1.txt @@ -1298,7 +1298,7 @@ Variable symbols changes summary: 0 Removed, 0 Added variable symbol not referen parameter 1 of type 'VarDesc*' has sub-type changes: in pointed to type 'struct VarDesc' at offload_common.h:254:1: type size hasn't changed - 1 data member changes (1 filtered): + 1 data member changes (2 filtered): type of 'union {struct {uint32_t is_static; uint32_t is_static_dstn; uint32_t has_length; uint32_t is_stack_buf; uint32_t sink_addr; uint32_t alloc_disp; uint32_t is_noncont_src; uint32_t is_noncont_dst;}; uint32_t bits;} VarDesc::flags' changed: type name changed from 'VarDesc::__anonymous_union__2' to 'varDescFlags' type size hasn't changed diff --git a/tests/data/test-diff-filter/test30-pr18904-rvalueref-report2.txt b/tests/data/test-diff-filter/test30-pr18904-rvalueref-report2.txt index 09fdb9c..e7bfbe2 100644 --- a/tests/data/test-diff-filter/test30-pr18904-rvalueref-report2.txt +++ b/tests/data/test-diff-filter/test30-pr18904-rvalueref-report2.txt @@ -1298,7 +1298,7 @@ Variable symbols changes summary: 0 Removed, 0 Added variable symbol not referen parameter 1 of type 'VarDesc*' has sub-type changes: in pointed to type 'struct VarDesc' at offload_common.h:254:1: type size hasn't changed - 1 data member changes (1 filtered): + 1 data member changes (2 filtered): type of 'union {struct {uint32_t is_static; uint32_t is_static_dstn; uint32_t has_length; uint32_t is_stack_buf; uint32_t sink_addr; uint32_t alloc_disp; uint32_t is_noncont_src; uint32_t is_noncont_dst;}; uint32_t bits;} VarDesc::flags' changed: type name changed from 'VarDesc::__anonymous_union__2' to 'varDescFlags' type size hasn't changed diff --git a/tests/data/test-diff-filter/test35-pr18754-no-added-syms-report-0.txt b/tests/data/test-diff-filter/test35-pr18754-no-added-syms-report-0.txt index 1f6e3e7..0c11fb6 100644 --- a/tests/data/test-diff-filter/test35-pr18754-no-added-syms-report-0.txt +++ b/tests/data/test-diff-filter/test35-pr18754-no-added-syms-report-0.txt @@ -214,7 +214,7 @@ Variable symbols changes summary: 0 Removed, 0 Added variable symbol not referen parameter 1 of type 'VarDesc*' has sub-type changes: in pointed to type 'struct VarDesc': type size hasn't changed - 1 data member changes (1 filtered): + 1 data member changes (2 filtered): type of 'union {struct {uint32_t is_static; uint32_t is_static_dstn; uint32_t has_length; uint32_t is_stack_buf; uint32_t sink_addr; uint32_t alloc_disp; uint32_t is_noncont_src; uint32_t is_noncont_dst;}; uint32_t bits;} VarDesc::flags' changed: type name changed from 'VarDesc::__anonymous_union__2' to 'varDescFlags' type size hasn't changed From patchwork Mon May 18 11:51:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dodji Seketeli X-Patchwork-Id: 39290 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id EE876388A83F; Mon, 18 May 2020 11:51:59 +0000 (GMT) X-Original-To: libabigail@sourceware.org Delivered-To: libabigail@sourceware.org Received: from relay7-d.mail.gandi.net (relay7-d.mail.gandi.net [217.70.183.200]) by sourceware.org (Postfix) with ESMTPS id 9D3E7388A825 for ; Mon, 18 May 2020 11:51:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 9D3E7388A825 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=seketeli.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=dodji@seketeli.org X-Originating-IP: 91.166.131.130 Received: from localhost (91-166-131-130.subs.proxad.net [91.166.131.130]) (Authenticated sender: dodj@seketeli.org) by relay7-d.mail.gandi.net (Postfix) with ESMTPSA id BFDC32000C for ; Mon, 18 May 2020 11:51:47 +0000 (UTC) Received: by localhost (Postfix, from userid 1001) id B640F1A033D; Mon, 18 May 2020 13:51:46 +0200 (CEST) From: Dodji Seketeli To: libabigail@sourceware.org Subject: [PATCH 3/3] Bug 25661 - Support data member replacement by anonymous data member Organization: Me, myself and I References: <86mu65a2i2.fsf@seketeli.org> X-Operating-System: Red Hat Enterprise Linux Server 7.7 X-URL: http://www.seketeli.net/~dodji X-Patchwork-State: Committed Date: Mon, 18 May 2020 13:51:46 +0200 In-Reply-To: <86mu65a2i2.fsf@seketeli.org> (Dodji Seketeli's message of "Mon, 18 May 2020 13:47:33 +0200") Message-ID: <86a725a2b1.fsf@seketeli.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3 (gnu/linux) MIME-Version: 1.0 X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, JMQ_SPF_NEUTRAL, KAM_DMARC_STATUS, KAM_LOTSOFHASH, KAM_STOCKGEN, LIKELY_SPAM_BODY, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libabigail@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list of the Libabigail project List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , Errors-To: libabigail-bounces@sourceware.org Sender: "Libabigail" Hello, We ought to detect when a data member is replaced by an anonymous data member in a way that doesn't change the ABI in an incompatible way, especially when that change is non equivocal. For instance, consider this ABI-visible struct: struct S { int a; }; Now, consider that it's changed into: struct S { union { int a; char b; }; }; Stricto sensu, the bit-layout of struct S doesn't change and so that change isn't ABI-incompatible. The current version of libabigail however flags that change as a /potential/ issue and asks the user for further review. It appears that this class of changes is frequent enough to be annoying, especially in semi-automatic ABI compliance checking setups where we want the least possible "false positives". This patch detects that kind of change patterns where a data member is replaced by an anonymous data member in a benign way, in terms of ABI. So now let's look at a more complicated example where an ABI-visible type looks like: struct S { int a; int b; int c; }; Now suppose that type was changed into: struct S { union { int tag[3]; struct { int a; int b; int c; }; }; }; The patch allows abidiff to recognise that kind of pattern, filter out the detected change and report by default that the two binaries are ABI compatible. Here are the output that we'd get: $ abidiff test-v0.o test-v1.o Functions changes summary: 0 Removed, 0 Changed (1 filtered out), 0 Added function Variables changes summary: 0 Removed, 0 Changed, 0 Added variable When asked to show the detailed of the filtered out changes, we get: $ abidiff --harmless test-v0.o test-v1.o 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 void foo(S*)' at test-v1.cc:18:1 has some indirect sub-type changes: parameter 1 of type 'S*' has sub-type changes: in pointed to type 'struct S' at test-v1.cc:1:1: type size hasn't changed data members 'S::a', 'S::b', 'S::c' were replaced by anonymous data member: 'union {int tag[3]; struct {int a; int b; int c;};}' And using the leaf-node reporter, that would give: $ abidiff --leaf-changes-only --harmless test-v0.o test-v1.o Leaf changes summary: 1 artifact changed Changed leaf types summary: 1 leaf type changed Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable 'struct S at test-v0.cc:1:1' changed: type size hasn't changed data members 'S::a', 'S::b', 'S::c' were replaced by anonymous data member: 'union {int tag[3]; struct {int a; int b; int c;};}' * include/abg-comp-filter.h (has_data_member_replaced_by_anon_dm): Declare new function. * include/abg-comparison.h (changed_var_sptr) (changed_var_sptrs_type): Declare new typedefs. (HARMLESS_DATA_MEMBER_CHANGE_CATEGORY): Add a new enumerator to the diff_category enum. (EVERYTHING_CATEGORY): In the diff_category, adjust this enumerator to OR the new HARMLESS_DATA_MEMBER_CHANGE_CATEGORY into it. (SUPPRESSED_CATEGORY, PRIVATE_TYPE_CATEGORY) (SIZE_OR_OFFSET_CHANGE_CATEGORY, VIRTUAL_MEMBER_CHANGE_CATEGORY) (CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY) (FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY) (FN_RETURN_TYPE_CV_CHANGE_CATEGORY, VAR_TYPE_CV_CHANGE_CATEGORY) (VOID_PTR_TO_PTR_CHANGE_CATEGORY) (BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY): Adjust the value of these enumerators of the diff_category enum. (class_or_union_diff::{data_members_replaced_by_adms, ordered_data_members_replaced_by_adms}): Declare new member functions. * include/abg-fwd.h (var_decl_wptr): Declare new typedef. (get_next_data_member, get_first_non_anonymous_data_member) (find_data_member_from_anonymous_data_member) (get_absolute_data_member_offset): Declare new functions. * include/abg-ir.h (struct anonymous_dm_hash): Declare new type. (anonymous_data_member_sptr_set_type): Declare new typedef. (class decl_base): Befriend class class_or_union. (class dm_context_rel): Pimpl-ify this class. (dm_context_rel::{g,s}et_anonymous_data_member_types): Declare new member functions. (var_decl::get_anon_dm_reliable_name): Declare new member function. (class var_decl): Make get_absolute_data_member_offset, get_absolute_data_member_offset be friends of this. (class_or_union::maybe_fixup_members_of_anon_data_member): Declare new protected member function. * src/abg-comp-filter.cc (has_data_member_replaced_by_anon_dm): Define new function. (categorize_harmless_diff_node): Use the above. * src/abg-comparison-priv.h (class_or_union_diff::priv::{dms_replaced_by_adms_, changed_var_sptrs_type dms_replaced_by_adms_ordered_}): Add new data members. (data_member_comp::compare_data_members): Factorize this out of ... (data_member_comp::operator()(decl_base_sptr&, decl_base_sptr&)): ... this. (data_member_comp::operator()(changed_var_sptr&, changed_var_sptr&)): Add new member function. (sort_changed_data_members): Declare ... * src/abg-comparison.cc (sort_changed_data_members): ... new function. (get_default_harmless_categories_bitmap): Adjust to take the new abigail::comparison::HARMLESS_DATA_MEMBER_CHANGE_CATEGORY into account. (operator<<(ostream& o, diff_category c)): Likewise. (class_or_union_diff::ensure_lookup_tables_populated): Handle Handle the insertion of anonymous data members to replace existing data members. (class_or_union_diff::{data_members_replaced_by_adms, ordered_data_members_replaced_by_adms}): Define new accessors. (suppression_categorization_visitor::visit_end): Propagate the SUPPRESSION_CATEGORIZATION_VISITOR from changes to the type of the data member if the data member doesn't have real local changes. * src/abg-default-reporter.cc (default_reporter::report): Report about anonymous data members that replace data members. * src/abg-ir.cc (struct dm_context_rel::priv): Define new data structure. (dm_context_rel::{dm_context_rel, get_is_laid_out, set_is_laid_out, get_offset_in_bits, set_offset_in_bits, operator==, operator!=, get_anonymous_data_member, set_anonymous_data_member}): Define the member functions here as they are not inline anymore. (class_or_union::maybe_fixup_members_of_anon_data_member): Define new member function. (class_or_union::add_data_member): Use it. (get_first_non_anonymous_data_member, get_next_data_member) (get_absolute_data_member_offset) (find_data_member_from_anonymous_data_member): Define new functions. * src/abg-reporter-priv.h (maybe_report_data_members_replaced_by_anon_dm): Declare ... * src/abg-reporter-priv.cc (maybe_report_data_members_replaced_by_anon_dm): ... new function. * src/abg-leaf-reporter.cc (leaf_reporter::report): Report data members replaced by anonymous data members. * tests/data/test-diff-filter/test-PR25661-[1-6]-report-[1-4].txt: New test reference outputs. * tests/data/test-diff-filter/test-PR25661-[1-6]-v{0,1}.c: Test source code files. * tests/data/test-diff-filter/test-PR25661-[1-6]-v{0,1}.o: Test binary input files. * tests/data/Makefile.am: Add the new test files above to source distribution. * tests/test-diff-filter.cc (in_out_specs): Add the binary test inputs above to this test harness. * tests/data/test-diff-dwarf/test45-anon-dm-change-report-0.txt: Adjust. Signed-off-by: Dodji Seketeli Applied to master. --- include/abg-comp-filter.h | 3 + include/abg-comparison.h | 48 +++- include/abg-fwd.h | 18 +- include/abg-ir.h | 65 +++-- src/abg-comp-filter.cc | 22 ++ src/abg-comparison-priv.h | 60 ++++- src/abg-comparison.cc | 262 ++++++++++++++++++-- src/abg-default-reporter.cc | 4 + src/abg-ir.cc | 270 ++++++++++++++++++++- src/abg-leaf-reporter.cc | 4 + src/abg-reporter-priv.cc | 85 ++++++- src/abg-reporter-priv.h | 6 + tests/data/Makefile.am | 48 ++++ .../test45-anon-dm-change-report-0.txt | 4 +- .../test-diff-filter/test-PR25661-1-report-1.txt | 3 + .../test-diff-filter/test-PR25661-1-report-2.txt | 12 + .../test-diff-filter/test-PR25661-1-report-3.txt | 5 + .../test-diff-filter/test-PR25661-1-report-4.txt | 9 + tests/data/test-diff-filter/test-PR25661-1-v0.c | 12 + tests/data/test-diff-filter/test-PR25661-1-v0.o | Bin 0 -> 2760 bytes tests/data/test-diff-filter/test-PR25661-1-v1.c | 20 ++ tests/data/test-diff-filter/test-PR25661-1-v1.o | Bin 0 -> 2960 bytes .../test-diff-filter/test-PR25661-2-report-1.txt | 3 + .../test-diff-filter/test-PR25661-2-report-2.txt | 12 + .../test-diff-filter/test-PR25661-2-report-3.txt | 5 + .../test-diff-filter/test-PR25661-2-report-4.txt | 9 + tests/data/test-diff-filter/test-PR25661-2-v0.c | 12 + tests/data/test-diff-filter/test-PR25661-2-v0.o | Bin 0 -> 2760 bytes tests/data/test-diff-filter/test-PR25661-2-v1.c | 22 ++ tests/data/test-diff-filter/test-PR25661-2-v1.o | Bin 0 -> 2968 bytes .../test-diff-filter/test-PR25661-3-report-1.txt | 3 + .../test-diff-filter/test-PR25661-3-report-2.txt | 12 + .../test-diff-filter/test-PR25661-3-report-3.txt | 5 + .../test-diff-filter/test-PR25661-3-report-4.txt | 9 + tests/data/test-diff-filter/test-PR25661-3-v0.c | 12 + tests/data/test-diff-filter/test-PR25661-3-v0.o | Bin 0 -> 2760 bytes tests/data/test-diff-filter/test-PR25661-3-v1.c | 23 ++ tests/data/test-diff-filter/test-PR25661-3-v1.o | Bin 0 -> 2920 bytes .../test-diff-filter/test-PR25661-4-report-1.txt | 3 + .../test-diff-filter/test-PR25661-4-report-2.txt | 12 + .../test-diff-filter/test-PR25661-4-report-3.txt | 5 + .../test-diff-filter/test-PR25661-4-report-4.txt | 9 + tests/data/test-diff-filter/test-PR25661-4-v0.c | 15 ++ tests/data/test-diff-filter/test-PR25661-4-v0.o | Bin 0 -> 3400 bytes tests/data/test-diff-filter/test-PR25661-4-v1.c | 21 ++ tests/data/test-diff-filter/test-PR25661-4-v1.o | Bin 0 -> 3480 bytes .../test-diff-filter/test-PR25661-5-report-1.txt | 3 + .../test-diff-filter/test-PR25661-5-report-2.txt | 12 + .../test-diff-filter/test-PR25661-5-report-3.txt | 5 + .../test-diff-filter/test-PR25661-5-report-4.txt | 9 + tests/data/test-diff-filter/test-PR25661-5-v0.c | 14 ++ tests/data/test-diff-filter/test-PR25661-5-v0.o | Bin 0 -> 3152 bytes tests/data/test-diff-filter/test-PR25661-5-v1.c | 25 ++ tests/data/test-diff-filter/test-PR25661-5-v1.o | Bin 0 -> 3280 bytes .../test-diff-filter/test-PR25661-6-report-1.txt | 3 + .../test-diff-filter/test-PR25661-6-report-2.txt | 5 + .../test-diff-filter/test-PR25661-6-report-3.txt | 12 + .../test-diff-filter/test-PR25661-6-report-4.txt | 9 + tests/data/test-diff-filter/test-PR25661-6-v0.c | 10 + tests/data/test-diff-filter/test-PR25661-6-v0.o | Bin 0 -> 2656 bytes tests/data/test-diff-filter/test-PR25661-6-v1.c | 14 ++ tests/data/test-diff-filter/test-PR25661-6-v1.o | Bin 0 -> 2792 bytes tests/test-diff-filter.cc | 168 +++++++++++++ 63 files changed, 1361 insertions(+), 80 deletions(-) create mode 100644 tests/data/test-diff-filter/test-PR25661-1-report-1.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-1-report-2.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-1-report-3.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-1-report-4.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-1-v0.c create mode 100644 tests/data/test-diff-filter/test-PR25661-1-v0.o create mode 100644 tests/data/test-diff-filter/test-PR25661-1-v1.c create mode 100644 tests/data/test-diff-filter/test-PR25661-1-v1.o create mode 100644 tests/data/test-diff-filter/test-PR25661-2-report-1.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-2-report-2.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-2-report-3.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-2-report-4.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-2-v0.c create mode 100644 tests/data/test-diff-filter/test-PR25661-2-v0.o create mode 100644 tests/data/test-diff-filter/test-PR25661-2-v1.c create mode 100644 tests/data/test-diff-filter/test-PR25661-2-v1.o create mode 100644 tests/data/test-diff-filter/test-PR25661-3-report-1.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-3-report-2.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-3-report-3.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-3-report-4.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-3-v0.c create mode 100644 tests/data/test-diff-filter/test-PR25661-3-v0.o create mode 100644 tests/data/test-diff-filter/test-PR25661-3-v1.c create mode 100644 tests/data/test-diff-filter/test-PR25661-3-v1.o create mode 100644 tests/data/test-diff-filter/test-PR25661-4-report-1.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-4-report-2.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-4-report-3.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-4-report-4.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-4-v0.c create mode 100644 tests/data/test-diff-filter/test-PR25661-4-v0.o create mode 100644 tests/data/test-diff-filter/test-PR25661-4-v1.c create mode 100644 tests/data/test-diff-filter/test-PR25661-4-v1.o create mode 100644 tests/data/test-diff-filter/test-PR25661-5-report-1.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-5-report-2.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-5-report-3.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-5-report-4.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-5-v0.c create mode 100644 tests/data/test-diff-filter/test-PR25661-5-v0.o create mode 100644 tests/data/test-diff-filter/test-PR25661-5-v1.c create mode 100644 tests/data/test-diff-filter/test-PR25661-5-v1.o create mode 100644 tests/data/test-diff-filter/test-PR25661-6-report-1.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-6-report-2.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-6-report-3.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-6-report-4.txt create mode 100644 tests/data/test-diff-filter/test-PR25661-6-v0.c create mode 100644 tests/data/test-diff-filter/test-PR25661-6-v0.o create mode 100644 tests/data/test-diff-filter/test-PR25661-6-v1.c create mode 100644 tests/data/test-diff-filter/test-PR25661-6-v1.o diff --git a/include/abg-comp-filter.h b/include/abg-comp-filter.h index b8da315..8113003 100644 --- a/include/abg-comp-filter.h +++ b/include/abg-comp-filter.h @@ -89,6 +89,9 @@ has_anonymous_data_member_change(const diff *d); bool has_anonymous_data_member_change(const diff_sptr &d); +bool +has_data_member_replaced_by_anon_dm(const diff* diff); + struct filter_base; /// Convenience typedef for a shared pointer to filter_base typedef shared_ptr filter_base_sptr; diff --git a/include/abg-comparison.h b/include/abg-comparison.h index cf95624..bb510a1 100644 --- a/include/abg-comparison.h +++ b/include/abg-comparison.h @@ -257,6 +257,15 @@ typedef unordered_map string_var_ptr_map; /// the changed variable. typedef std::pair changed_var_ptr; +/// Convenience typedef for a pair of @ref var_decl_sptr representing +/// a @ref var_decl change. The first member of the pair represents +/// the initial variable and the second member represents the changed +/// variable. +typedef std::pair changed_var_sptr; + +/// Convenience typedef for a vector of @changed_var_sptr.gg381 +typedef vector changed_var_sptrs_type; + /// Convenience typedef for a map whose key is a string and whose /// value is an @ref elf_symbol_sptr. typedef unordered_map string_elf_symbol_map; @@ -375,61 +384,69 @@ enum diff_category /// alias change that is harmless. HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY = 1 << 6, + /// This means that a diff node in the sub-tree carries a harmless + /// union change. HARMLESS_UNION_CHANGE_CATEGORY = 1 << 7, + /// This means that a diff node in the sub-tree carries a harmless + /// data member change. An example of harmless data member change + /// is an anonymous data member that replaces a given data member + /// without locally changing the layout. + HARMLESS_DATA_MEMBER_CHANGE_CATEGORY = 1 << 8, + /// This means that a diff node was marked as suppressed by a /// user-provided suppression specification. - SUPPRESSED_CATEGORY = 1 << 8, + SUPPRESSED_CATEGORY = 1 << 9, /// This means that a diff node was warked as being for a private /// type. That is, the diff node is meant to be suppressed by a /// suppression specification that was auto-generated to filter out /// changes to private types. - PRIVATE_TYPE_CATEGORY = 1 << 9, + PRIVATE_TYPE_CATEGORY = 1 << 10, /// This means the diff node (or at least one of its descendant /// nodes) carries a change that modifies the size of a type or an /// offset of a type member. Removal or changes of enumerators in a /// enum fall in this category too. - SIZE_OR_OFFSET_CHANGE_CATEGORY = 1 << 10, + SIZE_OR_OFFSET_CHANGE_CATEGORY = 1 << 11, /// This means that a diff node in the sub-tree carries an /// incompatible change to a vtable. - VIRTUAL_MEMBER_CHANGE_CATEGORY = 1 << 11, + VIRTUAL_MEMBER_CHANGE_CATEGORY = 1 << 12, /// A diff node in this category is redundant. That means it's /// present as a child of a other nodes in the diff tree. - REDUNDANT_CATEGORY = 1 << 12, + REDUNDANT_CATEGORY = 1 << 13, /// This means that a diff node in the sub-tree carries a class type /// that was declaration-only and that is now defined, or vice /// versa. - CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY = 1 << 13, + CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY = 1 << 14, /// A diff node in this category is a function parameter type which /// top cv-qualifiers change. - FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY = 1 << 14, + FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY = 1 << 15, /// A diff node in this category has a function parameter type with a /// cv-qualifiers change. - FN_PARM_TYPE_CV_CHANGE_CATEGORY = 1 << 15, + FN_PARM_TYPE_CV_CHANGE_CATEGORY = 1 << 16, /// A diff node in this category is a function return type with a /// cv-qualifier change. - FN_RETURN_TYPE_CV_CHANGE_CATEGORY = 1 << 16, + FN_RETURN_TYPE_CV_CHANGE_CATEGORY = 1 << 17, /// A diff node in this category is for a variable which type holds /// a cv-qualifier change. - VAR_TYPE_CV_CHANGE_CATEGORY = 1 << 17, + VAR_TYPE_CV_CHANGE_CATEGORY = 1 << 18, /// A diff node in this category carries a change from void pointer /// to non-void pointer. - VOID_PTR_TO_PTR_CHANGE_CATEGORY = 1 << 18, + VOID_PTR_TO_PTR_CHANGE_CATEGORY = 1 << 19, /// A diff node in this category carries a change in the size of the /// array type of a global variable, but the ELF size of the /// variable didn't change. - BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY = 1 << 19, + BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY = 1 << 20, /// A special enumerator that is the logical 'or' all the /// enumerators above. /// @@ -444,6 +461,7 @@ enum diff_category | HARMLESS_ENUM_CHANGE_CATEGORY | HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY | HARMLESS_UNION_CHANGE_CATEGORY + | HARMLESS_DATA_MEMBER_CHANGE_CATEGORY | SUPPRESSED_CATEGORY | PRIVATE_TYPE_CATEGORY | SIZE_OR_OFFSET_CHANGE_CATEGORY @@ -1610,6 +1628,12 @@ public: size_t count_filtered_subtype_changed_data_members(bool local_only = false) const; + const string_decl_base_sptr_map& + data_members_replaced_by_adms() const; + + const changed_var_sptrs_type& + ordered_data_members_replaced_by_adms() const; + const edit_script& member_fn_tmpls_changes() const; diff --git a/include/abg-fwd.h b/include/abg-fwd.h index 90a8114..f6e0c5b 100644 --- a/include/abg-fwd.h +++ b/include/abg-fwd.h @@ -223,6 +223,9 @@ class var_decl; /// Convenience typedef for a shared pointer on a @ref var_decl typedef shared_ptr var_decl_sptr; +/// Convenience typedef for a weak pointer on a @ref var_decl +typedef weak_ptr var_decl_wptr; + typedef unordered_map istring_var_decl_ptr_map_type; @@ -614,6 +617,9 @@ is_data_member(const decl_base *); var_decl* is_data_member(const decl_base *); +const var_decl_sptr +get_next_data_member(const class_or_union_sptr&, const var_decl_sptr&); + bool is_anonymous_data_member(const decl_base&); @@ -638,7 +644,14 @@ is_anonymous_data_member(const var_decl*); bool is_anonymous_data_member(const var_decl&); -const class_or_union* +const var_decl_sptr +get_first_non_anonymous_data_member(const var_decl_sptr); + +var_decl_sptr +find_data_member_from_anonymous_data_member(const var_decl_sptr&, + const string&); + +class_or_union* anonymous_data_member_to_class_or_union(const var_decl*); class_or_union_sptr @@ -678,6 +691,9 @@ uint64_t get_data_member_offset(const decl_base_sptr); uint64_t +get_absolute_data_member_offset(const var_decl&); + +uint64_t get_var_size_in_bits(const var_decl_sptr&); void diff --git a/include/abg-ir.h b/include/abg-ir.h index 15b0b40..ebcc4b8 100644 --- a/include/abg-ir.h +++ b/include/abg-ir.h @@ -1601,8 +1601,8 @@ public: friend void set_member_function_is_virtual(function_decl&, bool); + friend class class_or_union; friend class class_decl; - friend class scope_decl; };// end class decl_base @@ -2637,61 +2637,45 @@ public: class dm_context_rel : public context_rel { protected: - bool is_laid_out_; - size_t offset_in_bits_; + struct priv; + typedef shared_ptr priv_sptr; + + priv_sptr priv_; public: - dm_context_rel() - : context_rel(), - is_laid_out_(!is_static_), - offset_in_bits_(0) - {} + dm_context_rel(); dm_context_rel(scope_decl* s, bool is_laid_out, size_t offset_in_bits, access_specifier a, - bool is_static) - : context_rel(s, a, is_static), - is_laid_out_(is_laid_out), - offset_in_bits_(offset_in_bits) - {} + bool is_static); - dm_context_rel(scope_decl* s) - : context_rel(s), - is_laid_out_(!is_static_), - offset_in_bits_(0) - {} + dm_context_rel(scope_decl* s); bool - get_is_laid_out() const - {return is_laid_out_;} + get_is_laid_out() const; void - set_is_laid_out(bool f) - {is_laid_out_ = f;} + set_is_laid_out(bool f); size_t - get_offset_in_bits() const - {return offset_in_bits_;} + get_offset_in_bits() const; void - set_offset_in_bits(size_t o) - {offset_in_bits_ = o;} + set_offset_in_bits(size_t o); - bool - operator==(const dm_context_rel& o) const - { - if (!context_rel::operator==(o)) - return false; + const var_decl* + get_anonymous_data_member() const; - return (is_laid_out_ == o.is_laid_out_ - && offset_in_bits_ == o.offset_in_bits_); - } + void + set_anonymous_data_member(var_decl *); bool - operator!=(const dm_context_rel& o) const - {return !operator==(o);} + operator==(const dm_context_rel& o) const; + + bool + operator!=(const dm_context_rel& o) const; virtual ~dm_context_rel(); };// end class class_decl::dm_context_rel @@ -2783,6 +2767,12 @@ public: friend uint64_t get_data_member_offset(const var_decl& m); + friend uint64_t + get_absolute_data_member_offset(const var_decl& m); + + friend uint64_t + get_absolute_data_member_offset(const var_decl_sptr& m); + friend void set_data_member_is_laid_out(var_decl_sptr m, bool l); @@ -3731,6 +3721,9 @@ protected: virtual void remove_member_decl(decl_base_sptr); + void + maybe_fixup_members_of_anon_data_member(var_decl_sptr& anon_dm); + public: /// Hasher. struct hash; diff --git a/src/abg-comp-filter.cc b/src/abg-comp-filter.cc index 75df901..67c2a18 100644 --- a/src/abg-comp-filter.cc +++ b/src/abg-comp-filter.cc @@ -533,6 +533,25 @@ non_static_data_member_added_or_removed(const diff* diff) (dynamic_cast(diff)); } +/// Test if a @ref class_or_union_diff has a data member replaced by +/// an anonymous data member in a harmless way. That means, the new +/// anonymous data member somehow contains the replaced data member +/// and it doesn't break the layout of the containing class. +/// +/// @param diff the diff node to consider. +/// +/// @return true iff the @ref class_or_union_diff has a data member +/// harmlessly replaced by an anonymous data member. +bool +has_data_member_replaced_by_anon_dm(const diff* diff) +{ + const class_or_union_diff *c = is_class_or_union_diff(diff); + + if (!c) + return false; + return !c->data_members_replaced_by_adms().empty(); +} + /// Test if a class_diff node has static members added or removed. /// /// @param diff the diff node to consider. @@ -1521,6 +1540,9 @@ categorize_harmless_diff_node(diff *d, bool pre) || static_data_member_type_size_changed(f, s)) category |= STATIC_DATA_MEMBER_CHANGE_CATEGORY; + if (has_data_member_replaced_by_anon_dm(d)) + category |= HARMLESS_DATA_MEMBER_CHANGE_CATEGORY; + if ((has_enumerator_insertion(d) && !has_harmful_enum_change(d)) || has_harmless_enum_to_int_change(d)) diff --git a/src/abg-comparison-priv.h b/src/abg-comparison-priv.h index 565f024..420e701 100644 --- a/src/abg-comparison-priv.h +++ b/src/abg-comparison-priv.h @@ -502,6 +502,13 @@ struct class_or_union_diff::priv // member bar at offset N. unsigned_var_diff_sptr_map changed_dm_; var_diff_sptrs_type sorted_changed_dm_; + + // This is a data structure to represent data members that have been + // replaced by anonymous data members. It's a map that associates + // the name of the data member to the anonymous data member that + // replaced it. + string_decl_base_sptr_map dms_replaced_by_adms_; + mutable changed_var_sptrs_type dms_replaced_by_adms_ordered_; string_member_function_sptr_map deleted_member_functions_; string_member_function_sptr_map inserted_member_functions_; string_function_decl_diff_sptr_map changed_member_functions_; @@ -549,18 +556,18 @@ struct class_or_union_diff::priv /// offset. struct data_member_comp { - /// @param f the first data member to take into account. + + /// Compare two data members. /// - /// @param s the second data member to take into account. + /// First look at their offset and then their name. /// - /// @return true iff f is before s. + /// @parm first_dm the first data member to consider. + /// + /// @param second_dm the second data member to consider. bool - operator()(const decl_base_sptr& f, - const decl_base_sptr& s) const + compare_data_members(const var_decl_sptr& first_dm, + const var_decl_sptr& second_dm) const { - var_decl_sptr first_dm = is_data_member(f); - var_decl_sptr second_dm = is_data_member(s); - ABG_ASSERT(first_dm); ABG_ASSERT(second_dm); @@ -578,6 +585,40 @@ struct data_member_comp // sort them lexicographically. return first_dm_name < second_dm_name; } + + /// Compare two data members. + /// + /// First look at their offset and then their name. + /// + /// @parm first_dm the first data member to consider. + /// + /// @param second_dm the second data member to consider. + bool + operator()(const decl_base_sptr& f, + const decl_base_sptr& s) const + { + var_decl_sptr first_dm = is_data_member(f); + var_decl_sptr second_dm = is_data_member(s); + + return compare_data_members(first_dm, second_dm); + } + + /// Compare two data members. + /// + /// First look at their offset and then their name. + /// + /// @parm first_dm the first data member to consider. + /// + /// @param second_dm the second data member to consider. + bool + operator()(const changed_var_sptr& f, + const changed_var_sptr& s) const + { + var_decl_sptr first_dm = is_data_member(is_decl(f.first)); + var_decl_sptr second_dm = is_data_member(is_decl(s.first)); + + return compare_data_members(first_dm, second_dm); + } };//end struct data_member_comp /// The type of the private data (pimpl sub-object) of the @ref @@ -1347,6 +1388,9 @@ sort_data_members(const string_decl_base_sptr_map &data_members, vector& sorted); void +sort_changed_data_members(changed_var_sptrs_type& input); + +void sort_string_function_ptr_map(const string_function_ptr_map& map, vector& sorted); diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc index e1689e5..7305a71 100644 --- a/src/abg-comparison.cc +++ b/src/abg-comparison.cc @@ -171,8 +171,18 @@ sort_data_members(const string_decl_base_sptr_map &data_members, std::sort(sorted.begin(), sorted.end(), comp); } -/// Sort a an instance of @ref string_function_ptr_map map and stuff -/// a resulting sorted vector of pointers to function_decl. +/// Sort (in place) a vector of changed data members. +/// +/// @param to_sort the vector to sort. +void +sort_changed_data_members(changed_var_sptrs_type& to_sort) +{ + data_member_comp comp; + std::sort(to_sort.begin(), to_sort.end(), comp); +} + +/// Sort an instance of @ref string_function_ptr_map map and stuff a +/// resulting sorted vector of pointers to function_decl. /// /// @param map the map to sort. /// @@ -2946,6 +2956,7 @@ get_default_harmless_categories_bitmap() | abigail::comparison::HARMLESS_ENUM_CHANGE_CATEGORY | abigail::comparison::HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY | abigail::comparison::HARMLESS_UNION_CHANGE_CATEGORY + | abigail::comparison::HARMLESS_DATA_MEMBER_CHANGE_CATEGORY | abigail::comparison::CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY | abigail::comparison::FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY | abigail::comparison::FN_PARM_TYPE_CV_CHANGE_CATEGORY @@ -3033,6 +3044,14 @@ operator<<(ostream& o, diff_category c) emitted_a_category |= true; } + if (c & HARMLESS_DATA_MEMBER_CHANGE_CATEGORY) + { + if (emitted_a_category) + o << "|"; + o << "HARMLESS_DATA_MEMBER_CHANGE_CATEGORY"; + emitted_a_category |= true; + } + if (c & HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY) { if (emitted_a_category) @@ -4688,21 +4707,179 @@ class_or_union_diff::ensure_lookup_tables_populated(void) const var_decl_sptr added_dm = is_var_decl(d); string name = added_dm->get_anon_dm_reliable_name(); ABG_ASSERT(priv_->inserted_data_members_.find(name) - == priv_->inserted_data_members_.end()); - string_decl_base_sptr_map::const_iterator j = - priv_->deleted_data_members_.find(name); - if (j != priv_->deleted_data_members_.end()) + == priv_->inserted_data_members_.end()); + + bool ignore_added_anonymous_data_member = false; + if (is_anonymous_data_member(added_dm)) { - if (*j->second != *d) + // + // Handle insertion of anonymous data member to + // replace existing data members. + // + // For instance consider this: + // struct S + // { + // int a; + // int b; + // int c; + // };// end struct S + // + // Where the data members 'a' and 'b' are replaced + // by an anonymous data member without changing the + // effective bit layout of the structure: + // + // struct S + // { + // struct + // { + // union + // { + // int a; + // char a_1; + // }; + // union + // { + // int b; + // char b_1; + // }; + // }; + // int c; + // }; // end struct S + // + var_decl_sptr replaced_dm, replacing_dm; + bool added_anon_dm_changes_dm = false; + // The vector of data members replaced by anonymous + // data members. + vector dms_replaced_by_anon_dm; + + // + // Let's start collecting the set of data members + // which have been replaced by anonymous types in a + // harmless way. These are going to be collected into + // dms_replaced_by_anon_dm and, ultimately, into + // priv_->dms_replaced_by_adms_ + // + for (string_decl_base_sptr_map::const_iterator it = + priv_->deleted_data_members_.begin(); + it != priv_->deleted_data_members_.end(); + ++it) { - var_decl_sptr old_dm = is_var_decl(j->second); - priv_->subtype_changed_dm_[name]= - compute_diff(old_dm, added_dm, context()); + // We don't support this pattern for anonymous + // data members themselves being replaced. If + // that occurs then we'll just report it verbatim. + if (is_anonymous_data_member(it->second)) + continue; + + string deleted_dm_name = it->second->get_name(); + if ((replacing_dm = + find_data_member_from_anonymous_data_member(added_dm, + deleted_dm_name))) + { + // So it looks like replacing_dm might have + // replaced the data member which name is + // 'deleted_dm_name'. Let's look deeper to be + // sure. + // + // Note that replacing_dm is part (member) of + // an anonymous data member that might replace + // replaced_dm. + + // So let's get that replaced data member. + replaced_dm = is_var_decl(it->second); + size_t replaced_dm_offset = + get_data_member_offset(replaced_dm), + replacing_dm_offset = + get_absolute_data_member_offset(replacing_dm); + + if (replaced_dm_offset != replacing_dm_offset) + { + // So the replacing data member and the + // replaced data member don't have the + // same offset. This is not the pattern we + // are looking for. Rather, it looks like + // the anonymous data member has *changed* + // the data member. + added_anon_dm_changes_dm = true; + break; + } + + if (replaced_dm->get_type()->get_size_in_bits() + == replaced_dm->get_type()->get_size_in_bits()) + dms_replaced_by_anon_dm.push_back(replaced_dm); + else + { + added_anon_dm_changes_dm = true; + break; + } + } + } + + // Now walk dms_replaced_by_anon_dm to fill up + // priv_->dms_replaced_by_adms_ with the set of data + // members replaced by anonymous data members. + if (!added_anon_dm_changes_dm + && !dms_replaced_by_anon_dm.empty()) + { + // See if the added data member isn't too big. + type_base_sptr added_dm_type = added_dm->get_type(); + ABG_ASSERT(added_dm_type); + var_decl_sptr new_next_dm = + get_next_data_member(second_class_or_union(), + added_dm); + var_decl_sptr old_next_dm = + first_class_or_union()->find_data_member(new_next_dm); + + if (!old_next_dm + || (old_next_dm + && (get_absolute_data_member_offset(old_next_dm) + == get_absolute_data_member_offset(new_next_dm)))) + { + // None of the data members that are replaced + // by the added union should be considered as + // having been deleted. + ignore_added_anonymous_data_member = true; + for (vector::const_iterator i = + dms_replaced_by_anon_dm.begin(); + i != dms_replaced_by_anon_dm.end(); + ++i) + { + string n = (*i)->get_name(); + priv_->dms_replaced_by_adms_[n] = + added_dm; + priv_->deleted_data_members_.erase(n); + } + } } - priv_->deleted_data_members_.erase(j); } - else - priv_->inserted_data_members_[name] = d; + + if (!ignore_added_anonymous_data_member) + { + // Detect changed data members. + // + // A changed data member (that we shall name D) is a data + // member that satisfies the conditions below: + // + // 1/ It must have been added. + // + // 2/ It must have been deleted as well. + // + // 3/ It there must be a non-empty difference between the + // deleted D and the added D. + string_decl_base_sptr_map::const_iterator j = + priv_->deleted_data_members_.find(name); + if (j != priv_->deleted_data_members_.end()) + { + if (*j->second != *d) + { + var_decl_sptr old_dm = is_var_decl(j->second); + priv_->subtype_changed_dm_[name]= + compute_diff(old_dm, added_dm, context()); + } + priv_->deleted_data_members_.erase(j); + } + else + priv_->inserted_data_members_[name] = d; + } } } @@ -4987,6 +5164,47 @@ size_t class_or_union_diff::count_filtered_subtype_changed_data_members(bool local) const {return get_priv()->count_filtered_subtype_changed_dm(local);} +/// Get the map of data members that got replaced by anonymous data +/// members. +/// +/// The key of a map entry is the name of the replaced data member and +/// the value is the anonymous data member that replaces it. +/// +/// @return the map of data members replaced by anonymous data +/// members. +const string_decl_base_sptr_map& +class_or_union_diff::data_members_replaced_by_adms() const +{return get_priv()->dms_replaced_by_adms_;} + +/// Get an ordered vector of of data members that got replaced by +/// anonymous data members. +/// +/// This returns a vector of pair of two data members: the one that +/// was replaced, and the anonymous data member that replaced it. +/// +/// @return the sorted vector data members replaced by anonymous data members. +const changed_var_sptrs_type& +class_or_union_diff::ordered_data_members_replaced_by_adms() const +{ + if (priv_->dms_replaced_by_adms_ordered_.empty()) + { + for (string_decl_base_sptr_map::const_iterator it = + priv_->dms_replaced_by_adms_.begin(); + it != priv_->dms_replaced_by_adms_.end(); + ++it) + { + const var_decl_sptr dm = + first_class_or_union()->find_data_member(it->first); + ABG_ASSERT(dm); + changed_var_sptr changed_dm(dm, is_data_member(it->second)); + priv_->dms_replaced_by_adms_ordered_.push_back(changed_dm); + } + sort_changed_data_members(priv_->dms_replaced_by_adms_ordered_); + } + + return priv_->dms_replaced_by_adms_ordered_; +} + /// @return the edit script of the member function templates of the two /// @ref class_or_union. const edit_script& @@ -11424,8 +11642,8 @@ void propagate_categories(corpus_diff_sptr diff_tree) {propagate_categories(diff_tree.get());} -/// A tree node visitor that knows how to categorizes a given in the -/// SUPPRESSED_CATEGORY category and how to propagate that +/// A tree node visitor that knows how to categorizes a given diff +/// node in the SUPPRESSED_CATEGORY category and how to propagate that /// categorization. struct suppression_categorization_visitor : public diff_node_visitor { @@ -11501,6 +11719,12 @@ struct suppression_categorization_visitor : public diff_node_visitor // Note that all pointer/reference diff node changes are // potentially considered local, i.e, local changes of the // pointed-to-type are considered local to the pointer itself. + // + // Similarly, changes local to the type of function parameters, + // variables (and data members) and classe (that are not of + // LOCAL_NON_TYPE_CHANGE_KIND kind) and that have been + // suppressed can propagate their SUPPRESSED_CATEGORY-ness to + // those kinds of diff node. !(d->get_category() & SUPPRESSED_CATEGORY) && (!d->has_local_changes() || is_pointer_diff(d) @@ -11512,6 +11736,10 @@ struct suppression_categorization_visitor : public diff_node_visitor || (is_fn_parm_diff(d) && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))) || (is_function_type_diff(d) + && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))) + || (is_var_diff(d) + && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))) + || (is_class_diff(d) && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))))) { // Note that we handle private diff nodes differently from @@ -11544,8 +11772,8 @@ struct suppression_categorization_visitor : public diff_node_visitor has_private_child = true; else if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY) - // Propagation of the SUPPRESSED_CATEGORY is going - // to be handled later below. + // Propagation of the SUPPRESSED_CATEGORY has been + // handled above already. ; else has_non_private_child = true; diff --git a/src/abg-default-reporter.cc b/src/abg-default-reporter.cc index b59e8d6..80cb663 100644 --- a/src/abg-default-reporter.cc +++ b/src/abg-default-reporter.cc @@ -1016,6 +1016,10 @@ default_reporter::report(const class_or_union_diff& d, if ((*it)->to_be_reported()) represent(*it, ctxt, out, indent + " "); } + + // Report about data members replaced by an anonymous union data + // member. + maybe_report_data_members_replaced_by_anon_dm(d, out, indent); } // member types diff --git a/src/abg-ir.cc b/src/abg-ir.cc index 85c27e3..aefbd08 100644 --- a/src/abg-ir.cc +++ b/src/abg-ir.cc @@ -2537,8 +2537,98 @@ elf_symbol::version::operator=(const elf_symbol::version& o) // +// +struct dm_context_rel::priv +{ + bool is_laid_out_; + size_t offset_in_bits_; + var_decl* anonymous_data_member_; + + priv(bool is_static = false) + : is_laid_out_(!is_static), + offset_in_bits_(0), + anonymous_data_member_() + {} + + priv(bool is_laid_out, size_t offset_in_bits) + : is_laid_out_(is_laid_out), + offset_in_bits_(offset_in_bits), + anonymous_data_member_() + {} +}; //end struct dm_context_rel::priv + +dm_context_rel::dm_context_rel() + : context_rel(), + priv_(new priv) +{} + +dm_context_rel::dm_context_rel(scope_decl* s, + bool is_laid_out, + size_t offset_in_bits, + access_specifier a, + bool is_static) + : context_rel(s, a, is_static), + priv_(new priv(is_laid_out, offset_in_bits)) +{} + +dm_context_rel::dm_context_rel(scope_decl* s) + : context_rel(s), + priv_(new priv()) +{} + +bool +dm_context_rel::get_is_laid_out() const +{return priv_->is_laid_out_;} + +void +dm_context_rel::set_is_laid_out(bool f) +{priv_->is_laid_out_ = f;} + +size_t +dm_context_rel::get_offset_in_bits() const +{return priv_->offset_in_bits_;} + +void +dm_context_rel::set_offset_in_bits(size_t o) +{priv_->offset_in_bits_ = o;} + +bool +dm_context_rel::operator==(const dm_context_rel& o) const +{ + if (!context_rel::operator==(o)) + return false; + + return (priv_->is_laid_out_ == o.priv_->is_laid_out_ + && priv_->offset_in_bits_ == o.priv_->offset_in_bits_); +} + +bool +dm_context_rel::operator!=(const dm_context_rel& o) const +{return !operator==(o);} + +/// Return a non-nil value if this data member context relationship +/// has an anonymous data member. That means, if the data member this +/// relation belongs to is part of an anonymous data member. +/// +/// @return the containing anonymous data member of this data member +/// relationship. Nil if there is none. +const var_decl* +dm_context_rel::get_anonymous_data_member() const +{return priv_->anonymous_data_member_;} + +/// Set the containing anonymous data member of this data member +/// context relationship. That means that the data member this +/// relation belongs to is part of an anonymous data member. +/// +/// @param anon_dm the containing anonymous data member of this data +/// member relationship. Nil if there is none. +void +dm_context_rel::set_anonymous_data_member(var_decl* anon_dm) +{priv_->anonymous_data_member_ = anon_dm;} + dm_context_rel::~dm_context_rel() {} +// // @@ -4423,6 +4513,71 @@ is_data_member(const decl_base *d) return 0; } +/// Get the first non-anonymous data member of a given anonymous data +/// member. +/// +/// E.g: +/// +/// struct S +/// { +/// union // <-- for this anonymous data member, the function +/// // returns a. +/// { +/// int a; +/// charb; +/// }; +/// }; +/// +/// @return anon_dm the anonymous data member to consider. +/// +/// @return the first non-anonymous data member of @p anon_dm. If no +/// data member was found then this function returns @p anon_dm. +const var_decl_sptr +get_first_non_anonymous_data_member(const var_decl_sptr anon_dm) +{ + if (!anon_dm || !is_anonymous_data_member(anon_dm)) + return anon_dm; + + class_or_union_sptr klass = anonymous_data_member_to_class_or_union(anon_dm); + var_decl_sptr first = *klass->get_non_static_data_members().begin(); + + if (is_anonymous_data_member(first)) + return get_first_non_anonymous_data_member(first); + + return first; +} + +/// In the context of a given class or union, this function returns +/// the data member that is located after a given data member. +/// +/// @param klass the class or union to consider. +/// +/// @param the data member to consider. +/// +/// @return the data member that is located right after @p +/// data_member. +const var_decl_sptr +get_next_data_member(const class_or_union_sptr &klass, + const var_decl_sptr &data_member) +{ + if (!klass ||!data_member) + return var_decl_sptr(); + + for (class_or_union::data_members::const_iterator it = + klass->get_non_static_data_members().begin(); + it != klass->get_non_static_data_members().end(); + ++it) + if (**it == *data_member) + { + ++it; + if (it != klass->get_non_static_data_members().end()) + return get_first_non_anonymous_data_member(*it); + break; + } + + return var_decl_sptr(); +} + /// Test if a decl is an anonymous data member. /// /// @param d the decl to consider. @@ -4544,7 +4699,7 @@ is_anonymous_data_member(const var_decl& d) /// /// @return the @ref class_or_union type of the anonymous data member /// @p d. -const class_or_union* +class_or_union* anonymous_data_member_to_class_or_union(const var_decl* d) { if ((d = is_anonymous_data_member(d))) @@ -4657,6 +4812,53 @@ uint64_t get_data_member_offset(const decl_base_sptr d) {return get_data_member_offset(dynamic_pointer_cast(d));} +/// Get the absolute offset of a data member. +/// +/// If the data member is part of an anonymous data member then this +/// returns the absolute offset -- relative to the beginning of the +/// containing class of the anonymous data member. +/// +/// @param m the data member to consider. +/// +/// @return the aboslute offset of the data member @p m. +uint64_t +get_absolute_data_member_offset(const var_decl& m) +{ + ABG_ASSERT(is_data_member(m)); + const dm_context_rel* ctxt_rel = + dynamic_cast(m.get_context_rel()); + ABG_ASSERT(ctxt_rel); + + const var_decl *containing_anonymous_data_member = + ctxt_rel->get_anonymous_data_member(); + + uint64_t containing_anonymous_data_member_offset = 0; + if (containing_anonymous_data_member) + containing_anonymous_data_member_offset = + get_absolute_data_member_offset(*containing_anonymous_data_member); + + return (ctxt_rel->get_offset_in_bits() + + + containing_anonymous_data_member_offset); +} + +/// Get the absolute offset of a data member. +/// +/// If the data member is part of an anonymous data member then this +/// returns the absolute offset -- relative to the beginning of the +/// containing class of the anonymous data member. +/// +/// @param m the data member to consider. +/// +/// @return the aboslute offset of the data member @p m. +uint64_t +get_absolute_data_member_offset(const var_decl_sptr& m) +{ + if (!m) + return 0; + return get_absolute_data_member_offset(*m); +} + /// Get the size of a given variable. /// /// @param v the variable to consider. @@ -5621,7 +5823,7 @@ canonical_type_hash::operator()(const type_base_sptr& l) const /// /// @param l the canonical type to hash. /// -/// @return the the pointer value of the canonical type of @p l. +/// @return the pointer value of the canonical type of @p l. size_t canonical_type_hash::operator()(const type_base *l) const {return reinterpret_cast(l);} @@ -7405,6 +7607,29 @@ is_at_class_scope(const decl_base& decl) return 0; } +/// Find a data member inside an anonymous data member. +/// +/// An anonymous data member has a type which is a class or union. +/// This function looks for a data member inside the type of that +/// anonymous data member. +/// +/// @param anon_dm the anonymous data member to consider. +/// +/// @param name the name of the data member to look for. +var_decl_sptr +find_data_member_from_anonymous_data_member(const var_decl_sptr& anon_dm, + const string& name) +{ + const class_or_union* containing_class_or_union = + anonymous_data_member_to_class_or_union(anon_dm.get()); + + if (!containing_class_or_union) + return var_decl_sptr(); + + var_decl_sptr result = containing_class_or_union->find_data_member(name); + return result; +} + /// Tests whether a given decl is at template scope. /// /// Note that only template parameters , types that are compositions, @@ -18119,6 +18344,39 @@ class_or_union::remove_member_decl(decl_base_sptr decl) remove_member_type(t); } +/// Fixup the members of the type of an anonymous data member. +/// +/// Walk all data members of (the type of) a given anonymous data +/// member and set a particular property of the relationship between +/// each data member and its containing type. +/// +/// That property records the fact that the data member belongs to the +/// anonymous data member we consider. +/// +/// In the future, if there are other properties of this relationship +/// to set in this manner, they ought to be added here. +/// +/// @param anon_dm the anonymous data member to consider. +void +class_or_union::maybe_fixup_members_of_anon_data_member(var_decl_sptr& anon_dm) +{ + class_or_union * anon_dm_type = + anonymous_data_member_to_class_or_union(anon_dm.get()); + if (!anon_dm_type) + return; + + for (class_or_union::data_members::const_iterator it = + anon_dm_type->get_non_static_data_members().begin(); + it != anon_dm_type->get_non_static_data_members().end(); + ++it) + { + dm_context_rel *rel = + dynamic_cast((*it)->get_context_rel()); + ABG_ASSERT(rel); + rel->set_anonymous_data_member(anon_dm.get()); + } +} + /// Insert a member type. /// /// @param t the type to insert in the @ref class_or_union type. @@ -18479,7 +18737,6 @@ class_or_union::add_data_member(var_decl_sptr v, access_specifier access, set_member_access_specifier(v, access); set_member_is_static(v, is_static); - if (!is_static) { // If this is a non-static variable, add it to the set of @@ -18497,6 +18754,13 @@ class_or_union::add_data_member(var_decl_sptr v, access_specifier access, if (!is_already_in) priv_->non_static_data_members_.push_back(v); } + + // If v is an anonymous data member, then fixup its data members. + // For now, the only thing the fixup does is to make the data + // members of the anonymous data member be aware of their containing + // anonymous data member. That is helpful to compute the absolute + // bit offset of each of the members of the anonymous data member. + maybe_fixup_members_of_anon_data_member(v); } /// Get the data members of this @ref class_or_union. diff --git a/src/abg-leaf-reporter.cc b/src/abg-leaf-reporter.cc index afe5692..f9d905a 100644 --- a/src/abg-leaf-reporter.cc +++ b/src/abg-leaf-reporter.cc @@ -631,6 +631,10 @@ leaf_reporter::report(const class_or_union_diff& d, if (diff_to_be_reported((*it).get())) represent(*it, ctxt, out, indent + " ", /*local_only=*/true); } + + // Report about data members replaced by an anonymous union data + // member. + maybe_report_data_members_replaced_by_anon_dm(d, out, indent); } } diff --git a/src/abg-reporter-priv.cc b/src/abg-reporter-priv.cc index df7df88..9f2c5a4 100644 --- a/src/abg-reporter-priv.cc +++ b/src/abg-reporter-priv.cc @@ -1415,5 +1415,88 @@ bool reporter_base::diff_to_be_reported(const diff *d) const {return d && d->to_be_reported();} -} // namespace comparison +/// Report about data members replaced by an anonymous data member +/// without changing the overall bit-layout of the class or union in +/// an ABI-meaningful way. +/// +/// @param d the diff to consider. +/// +/// @param out the output stream to emit the change report to. +/// +/// @param indent the indentation string to use. +void +maybe_report_data_members_replaced_by_anon_dm(const class_or_union_diff &d, + ostream &out, + const string indent) +{ + const diff_context_sptr& ctxt = d.context(); + + if ((ctxt->get_allowed_category() & HARMLESS_DATA_MEMBER_CHANGE_CATEGORY) + && !d.data_members_replaced_by_adms().empty()) + { + // Let's detect all the data members that are replaced by + // members of the same anonymous data member and report them + // in one go. + changed_var_sptrs_type::const_iterator i, j; + i = d.ordered_data_members_replaced_by_adms().begin(); + // This contains the data members replaced by the same + // anonymous data member. + vector dms_replaced_by_same_anon_dm; + // This contains the anonymous data member that replaced the + // data members in the variable above. + var_decl_sptr anonymous_data_member; + + while (i != d.ordered_data_members_replaced_by_adms().end()) + { + anonymous_data_member = i->second; + // Let's look forward to see if the subsequent data + // members were replaced by members of + // anonymous_data_member. + for (j = i; + j != d.ordered_data_members_replaced_by_adms().end(); + ++j) + { + if (*i->second == *j->second) + dms_replaced_by_same_anon_dm.push_back(j->first); + else + break; + } + + bool several_data_members_replaced = + dms_replaced_by_same_anon_dm.size() > 1; + + out << indent << "data member"; + if (several_data_members_replaced) + out << "s"; + + bool first_data_member = true; + for (vector::const_iterator it = + dms_replaced_by_same_anon_dm.begin(); + it != dms_replaced_by_same_anon_dm.end(); + ++it) + { + string name = (*it)->get_qualified_name(); + if (!first_data_member) + out << ","; + out << " '" << name << "'"; + first_data_member = false; + } + + if (several_data_members_replaced) + out << " were "; + else + out << " was "; + + out << "replaced by anonymous data member:\n" + << indent + " " + << "'" + << i->second->get_pretty_representation() + << "'\n"; + + i = j; + } + } +} + +} // Namespace comparison } // end namespace abigail diff --git a/src/abg-reporter-priv.h b/src/abg-reporter-priv.h index b221fdc..84cb238 100644 --- a/src/abg-reporter-priv.h +++ b/src/abg-reporter-priv.h @@ -250,6 +250,12 @@ maybe_report_interfaces_impacted_by_diff(const diff_sptr &d, ostream &out, const string &indent); +void +maybe_report_data_members_replaced_by_anon_dm(const class_or_union_diff &d, + ostream &out, + const string indent); + + } // end namespace comparison } // end namespace abigail diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 7e91f52..f5b551b 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -778,6 +778,54 @@ test-diff-filter/PR24787-libtwo.so \ test-diff-filter/PR24787-one.c \ test-diff-filter/PR24787-two.c \ test-diff-filter/PR24787-report-0.txt \ +test-diff-filter/test-PR25661-1-report-1.txt \ +test-diff-filter/test-PR25661-1-report-2.txt \ +test-diff-filter/test-PR25661-1-report-3.txt \ +test-diff-filter/test-PR25661-1-report-4.txt \ +test-diff-filter/test-PR25661-1-v0.o \ +test-diff-filter/test-PR25661-1-v1.o \ +test-diff-filter/test-PR25661-1-v0.c \ +test-diff-filter/test-PR25661-1-v1.c \ +test-diff-filter/test-PR25661-2-report-1.txt \ +test-diff-filter/test-PR25661-2-report-2.txt \ +test-diff-filter/test-PR25661-2-report-3.txt \ +test-diff-filter/test-PR25661-2-report-4.txt \ +test-diff-filter/test-PR25661-2-v0.o \ +test-diff-filter/test-PR25661-2-v1.o \ +test-diff-filter/test-PR25661-2-v0.c \ +test-diff-filter/test-PR25661-2-v1.c \ +test-diff-filter/test-PR25661-3-report-1.txt \ +test-diff-filter/test-PR25661-3-report-2.txt \ +test-diff-filter/test-PR25661-3-report-3.txt \ +test-diff-filter/test-PR25661-3-report-4.txt \ +test-diff-filter/test-PR25661-3-v0.o \ +test-diff-filter/test-PR25661-3-v1.o \ +test-diff-filter/test-PR25661-3-v0.c \ +test-diff-filter/test-PR25661-3-v1.c \ +test-diff-filter/test-PR25661-4-report-1.txt \ +test-diff-filter/test-PR25661-4-report-2.txt \ +test-diff-filter/test-PR25661-4-report-3.txt \ +test-diff-filter/test-PR25661-4-report-4.txt \ +test-diff-filter/test-PR25661-4-v0.o \ +test-diff-filter/test-PR25661-4-v1.o \ +test-diff-filter/test-PR25661-4-v0.c \ +test-diff-filter/test-PR25661-4-v1.c \ +test-diff-filter/test-PR25661-5-v0.o \ +test-diff-filter/test-PR25661-5-v1.o \ +test-diff-filter/test-PR25661-5-v0.c \ +test-diff-filter/test-PR25661-5-v1.c \ +test-diff-filter/test-PR25661-5-report-1.txt \ +test-diff-filter/test-PR25661-5-report-2.txt \ +test-diff-filter/test-PR25661-5-report-3.txt \ +test-diff-filter/test-PR25661-5-report-4.txt \ +test-diff-filter/test-PR25661-6-v0.c \ +test-diff-filter/test-PR25661-6-v1.c \ +test-diff-filter/test-PR25661-6-v0.o \ +test-diff-filter/test-PR25661-6-v1.o \ +test-diff-filter/test-PR25661-6-report-1.txt \ +test-diff-filter/test-PR25661-6-report-2.txt \ +test-diff-filter/test-PR25661-6-report-3.txt \ +test-diff-filter/test-PR25661-6-report-4.txt \ \ test-diff-suppr/test0-type-suppr-v0.cc \ test-diff-suppr/test0-type-suppr-v1.cc \ diff --git a/tests/data/test-diff-dwarf/test45-anon-dm-change-report-0.txt b/tests/data/test-diff-dwarf/test45-anon-dm-change-report-0.txt index 4ffd8b3..ada9d3a 100644 --- a/tests/data/test-diff-dwarf/test45-anon-dm-change-report-0.txt +++ b/tests/data/test-diff-dwarf/test45-anon-dm-change-report-0.txt @@ -18,6 +18,6 @@ Variables changes summary: 0 Removed, 0 Changed, 0 Added variable parameter 1 of type 'S0&' has sub-type changes: in referenced type 'struct S0': type size hasn't changed - 1 data member change: - data member int S0::m0 at offset 0 (in bits) became anonymous data member 'union {int m0; char m01;}' + data member 'S0::m0' was replaced by anonymous data member: + 'union {int m0; char m01;}' diff --git a/tests/data/test-diff-filter/test-PR25661-1-report-1.txt b/tests/data/test-diff-filter/test-PR25661-1-report-1.txt new file mode 100644 index 0000000..9666a8f --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-1-report-1.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-diff-filter/test-PR25661-1-report-2.txt b/tests/data/test-diff-filter/test-PR25661-1-report-2.txt new file mode 100644 index 0000000..3d9f663 --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-1-report-2.txt @@ -0,0 +1,12 @@ +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 void foo(S*)' at test-PR25661-1-v1.c:18:1 has some indirect sub-type changes: + parameter 1 of type 'S*' has sub-type changes: + in pointed to type 'struct S' at test-PR25661-1-v1.c:1:1: + type size hasn't changed + data members 'S::a', 'S::b', 'S::c' were replaced by anonymous data member: + 'union {int tag[3]; struct {int a; int b; int c;};}' + diff --git a/tests/data/test-diff-filter/test-PR25661-1-report-3.txt b/tests/data/test-diff-filter/test-PR25661-1-report-3.txt new file mode 100644 index 0000000..0927b7a --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-1-report-3.txt @@ -0,0 +1,5 @@ +Leaf changes summary: 0 artifact changed (1 filtered out) +Changed leaf types summary: 0 (1 filtered out) leaf type changed +Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function +Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable + diff --git a/tests/data/test-diff-filter/test-PR25661-1-report-4.txt b/tests/data/test-diff-filter/test-PR25661-1-report-4.txt new file mode 100644 index 0000000..577aff8 --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-1-report-4.txt @@ -0,0 +1,9 @@ +Leaf changes summary: 1 artifact changed +Changed leaf types summary: 1 leaf type changed +Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function +Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable + +'struct S at test-PR25661-1-v0.c:1:1' changed: + type size hasn't changed + data members 'S::a', 'S::b', 'S::c' were replaced by anonymous data member: + 'union {int tag[3]; struct {int a; int b; int c;};}' diff --git a/tests/data/test-diff-filter/test-PR25661-1-v0.c b/tests/data/test-diff-filter/test-PR25661-1-v0.c new file mode 100644 index 0000000..9c672ba --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-1-v0.c @@ -0,0 +1,12 @@ +struct S +{ + int a; + int b; + int c; + int d; +}; + +void +foo(struct S* s __attribute__((unused))) +{ +} diff --git a/tests/data/test-diff-filter/test-PR25661-1-v0.o b/tests/data/test-diff-filter/test-PR25661-1-v0.o new file mode 100644 index 0000000000000000000000000000000000000000..202c0673d80383920ecd2333224afbc6e6072ed4 GIT binary patch literal 2760 zcmbtVTW=dh6h7neWt&Z0CkD|dJS-BZO~tM+KyZsv3=wGx2t}zX^#z5sy|x#8LH4$U zn|J^r^{thV0D*)MFFYas13!ajB*YtUNIbwfvvcCfWFrualN-l(=PX#R0<-D|FN01AP4 zex0=!*C|H(!sjoplV7o5_~kADl+L5y4b;GsR0ZV+jA0C}*q{{L#jk|R_!Z*M@(O;{ z?%+xVB+)$a_Ya!SY;86ChJUvnbd^s*z_~OBIWLKia}xcstZT#RII8ugy*K09AWmwd zxD$5bK^Tu}I&O{J=Cxj!gbMn-xZn5t@hFLAaQ(Gg-cI9LuTc-`LBng-oAvrr&6aoR zAnJL0VWJg2DjS=gKThsUqU}L6iDq#Zr{SzS+&*e;`CCtW{s7?m&dycu5(eG;cM)-Q z52*!XGu}G@aa0i-%O&SNHs?{~=|@Ag_Jwlg)7;KVaTg6zI`c~>C=b8?m8HZcX3@Ak z$IU*Wm#E1aQeO*OC&9Q>hEhVwm@S}$bBl?AWV&L5Nuh+5QydWz%4hJWt}Hx^mTN{I zj*o5D>7q-i2d``i=Zs0k8HlIV+$0jmYAS$vJyrP$Gtc|Kt_^61%-z`3JlUK3o}6LN zwUK>6+mNVeY{$QH2JdN}YBB49VE*nn2|Fm0St^H&lISRbfNmNDo%tMsSu_fRUeviW zIE*L#De4psJDpi{_k=o}g_A*a(q$A+B6h(P5Ok;GafFX$FqtM%fY;2QCt>$39Vi+e z_GjT(y}P>j{~+d0F$3zMqX!2#67{j(bL|s?tjw*LqEGB^Lh{}b(RnZXYy9)pFJ^D^_L_P5P{)I^I7 zwdD0P{TYI+{_SP-k6wTF=e|-sc5aIOt0wn#!Sqhkzl!Zodt%=`q@YDb;o$c=ot-`_ S6gSKN4PF0t?5L&PzrO*xO1jSg literal 0 HcmV?d00001 diff --git a/tests/data/test-diff-filter/test-PR25661-1-v1.c b/tests/data/test-diff-filter/test-PR25661-1-v1.c new file mode 100644 index 0000000..24346b9 --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-1-v1.c @@ -0,0 +1,20 @@ +struct S +{ + union + { + int tag[3]; + struct + { + int a; + int b; + int c; + }; + }; + + int d; +}; + +void +foo(struct S* s __attribute__((unused))) +{ +} diff --git a/tests/data/test-diff-filter/test-PR25661-1-v1.o b/tests/data/test-diff-filter/test-PR25661-1-v1.o new file mode 100644 index 0000000000000000000000000000000000000000..28bb43d96bbde31452b190960d280810b594dc22 GIT binary patch literal 2960 zcmbtWO^72!6n>S;PiH#m$t23|FdlkA*_ma#^P`TlE3-xiXJ=NCab&@RGIo+q(wcN6 z=~>4W@t_DR2)iJtAb9ZZMer&~rr@7;d&`=1fc#v&v3P>OkFFcm&i zV)@+52yhRWVG;+t1FRUcS>6S<5VHnkv$-IQAXj3X-$b>13tjuZ8ZfyfyW*-LAykc?#Aa`a?HLt4T zM#`{@4h+V2YvieT4%c<`upm5GxSty1h8nI!Mii#(vZt11odM>jkgSCQ#q2hY94_F<*dJCI$GCH_h72Nq7CC$St;g5bn@-cY z(R919O^!h^i9yCy_I`$=-DnaH?89&t3_`zW)A81ald)g#O?s~f^+6ETM?uHy1OqP^ z)rHqOg_zZQUgX8B(+m22ryq52;BNpi9 zKCq(-TPYQc+gPxN5T_qeT<)i>%7>Y)a(){X5;%3Fe$B$~_tS(}*fbcA?DzoY_!8`4pDuWAmpF$7`(9g9ucWIvlrhT7S|L zAV}_P0oRfzk&Hk%?dC-Sk(QDPB>tsXQ+y(cSCb_yi9$< z{NX`=>WzJo`2U<%(4J}~>nYu}1#{d_Voka#ox=rT`ptSyRZ@7}{yfU45B{rt6K!>$ z6i&wfg%%3wy7Wn)k9b?rA=VI0^_{?}uSie!EPhvF+Qd=!NrH<4yc=ts47%3#5Cq~UD{__{y&KPr9I_Oua=&F4>8>*Lg0wYaE%rU>ALhkBQ5?t5ntAc;?up> z@^Y+2C( literal 0 HcmV?d00001 diff --git a/tests/data/test-diff-filter/test-PR25661-2-report-1.txt b/tests/data/test-diff-filter/test-PR25661-2-report-1.txt new file mode 100644 index 0000000..9666a8f --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-2-report-1.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-diff-filter/test-PR25661-2-report-2.txt b/tests/data/test-diff-filter/test-PR25661-2-report-2.txt new file mode 100644 index 0000000..31ce245 --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-2-report-2.txt @@ -0,0 +1,12 @@ +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 void foo(S*)' at test-PR25661-2-v1.c:20:1 has some indirect sub-type changes: + parameter 1 of type 'S*' has sub-type changes: + in pointed to type 'struct S' at test-PR25661-2-v1.c:1:1: + type size hasn't changed + data members 'S::b', 'S::c' were replaced by anonymous data member: + 'struct {int b; struct {union {char added_char; int c;};};}' + diff --git a/tests/data/test-diff-filter/test-PR25661-2-report-3.txt b/tests/data/test-diff-filter/test-PR25661-2-report-3.txt new file mode 100644 index 0000000..0927b7a --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-2-report-3.txt @@ -0,0 +1,5 @@ +Leaf changes summary: 0 artifact changed (1 filtered out) +Changed leaf types summary: 0 (1 filtered out) leaf type changed +Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function +Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable + diff --git a/tests/data/test-diff-filter/test-PR25661-2-report-4.txt b/tests/data/test-diff-filter/test-PR25661-2-report-4.txt new file mode 100644 index 0000000..9540c0a --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-2-report-4.txt @@ -0,0 +1,9 @@ +Leaf changes summary: 1 artifact changed +Changed leaf types summary: 1 leaf type changed +Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function +Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable + +'struct S at test-PR25661-2-v0.c:1:1' changed: + type size hasn't changed + data members 'S::b', 'S::c' were replaced by anonymous data member: + 'struct {int b; struct {union {char added_char; int c;};};}' diff --git a/tests/data/test-diff-filter/test-PR25661-2-v0.c b/tests/data/test-diff-filter/test-PR25661-2-v0.c new file mode 100644 index 0000000..9c672ba --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-2-v0.c @@ -0,0 +1,12 @@ +struct S +{ + int a; + int b; + int c; + int d; +}; + +void +foo(struct S* s __attribute__((unused))) +{ +} diff --git a/tests/data/test-diff-filter/test-PR25661-2-v0.o b/tests/data/test-diff-filter/test-PR25661-2-v0.o new file mode 100644 index 0000000000000000000000000000000000000000..8f3768c5fb6b5649bbdc6c2dbe2031fab98516ae GIT binary patch literal 2760 zcmbtV&1)n@6n`}}AHC^hc9K!t5DzUVyAiwRLyfa5*&PjLv#UsmEO?RFGgC9uIv+CA zyT&g(D8e3uT@X|hM7($s{|EmJ&w_aKCV0^Is_SJsl@5wNn0~K*@3UUjtNHMSmv(bP z0F!{Luvjq);1m~fTZ?U|!W!J#yZg)D-4Fh__u5ZiA)MDLM@LxJa_ZxzBCo}~?1Ct0(UCn6MJ+BvK3|9?F%N=lcj`e``xFG6OLCC&lK3bm(XTd~j#aHU?Y$Az22ora zMV+t{4Z>(tGcjrua9-<$ai~SV7xnvoKN`hq2G?J{pMGFyi1s9^WSB` z-94Z;jLmrW0K`#6Y%G_Yd)SmT=87sW=1Sw3}-LBCRG282{9)DL)b8$qHcI2y{Z})7UgP*{9Dv zKEs}CBm07}AyzT69slwfxMy&xC0!2$^LNH^*g+o85a-koIx}_WggTsslYu(vGKwaOT`&a%-RXF&@UaXg(^v&KX8t@5yKkC6 zYIxY6g=78hn&STl+dyCH759@vwT*CmZ_L`BtVa+h%$}eZjlIom|BGlq=lx&(8|Z7t zq@0}p8(O5uwxwsD{`}f08xmhl{t@AOgVVhti0>x;S7_SCuN{*VziBPN+lDi&&3`mN ziwzCu{WJU-3R(Tz%jh4y{_M|vrF!h#6#G{L?wf+?ou+>k+n>(Fo;`%1MMWX;d!4LK T-xZ3R<^Q^=|2uXx-0t7soGrUI literal 0 HcmV?d00001 diff --git a/tests/data/test-diff-filter/test-PR25661-2-v1.c b/tests/data/test-diff-filter/test-PR25661-2-v1.c new file mode 100644 index 0000000..f8eee3d --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-2-v1.c @@ -0,0 +1,22 @@ +struct S +{ + int a; + struct + { + int b; + struct + { + union + { + char added_char; + int c; + }; + }; + }; + int d; +}; + +void +foo(struct S* s __attribute__((unused))) +{ +} diff --git a/tests/data/test-diff-filter/test-PR25661-2-v1.o b/tests/data/test-diff-filter/test-PR25661-2-v1.o new file mode 100644 index 0000000000000000000000000000000000000000..0dbbc1faa6700ce64d9638d7c485e17d268650e3 GIT binary patch literal 2968 zcmbtV&2Jk;6o2Dg+v}|DI&n}F1tB9qZBTdp0iuI;7%K=!r@ zAjAPw(OZ#_5E3`82#E{-00*udBP0$S_yZ7^N*v(5*?IALvJnVI+L`x$?{nVF+xh6l zS9UW(01pAzV8$^DaGaab+mhUdDlEaxy?ejy-TUyt{kMMj1z}T)Ea{;r>BM9w=!_`} z`BxDz2o$!Y%?^lS?hQh+LI%v4*>Ds=-W2)lErczHgpjv{Y1~Dk&<2q!NDJ#t-i{goL z)i%m&@_6D*hvet~vJ`T2h4ebGPinMSq)j1bd z32sz3F`Gitn1F?f6#hnW25P`oI6doBWo3&P>)o47`+N@nX2>jZf7b$^*!sdF-8Ai89!B#IA1(UFY ztT*ZOw~jV9oQz%|+RfVp;#iCq zVEiS;Q+yhXbNtm9mYF3_V_o5-pFH==2|QWFeGUIc@!zYJZa~sM?}hwll@2WxMeF)k z&cJI5C*Mi`;7;EgMqV4&XcDh|rlQ~|0+$*V-1c+|?j#s^t{=2-_YT8RcZ@Pgd+qil zxHBjACf=wQ%$p3tQNSh`0^H7cI1KPLa7W`PaIqiRyKP1AIWw+z;-e@aOg?X{gzL)*I!WsG7f?v|W?iE3Nm+_^MV+&{9CkZYo@JFdNn{-{e_c}(}e<-jqGnJICOZ!aA z|0mTHY)|>q-%QWnM@;vL5Im-uf%~5@8oKTwVrlXDLUElaKJ~jE|6S#i^F&sTp^E<< z18U{?yncW<(YpO3>O!^t!Tu9vuc^Vlej$|t$7TI5mHphm12MMWWJR^|{u%xpiM0By zsD@0|k6sJ5XPolUW0UVsRsQ=bVfwGrE2P`gnWSy?n3BT5|M!?Xeg5P(&Ay@X|C$Ze Hs@Lytw-L>m literal 0 HcmV?d00001 diff --git a/tests/data/test-diff-filter/test-PR25661-3-report-1.txt b/tests/data/test-diff-filter/test-PR25661-3-report-1.txt new file mode 100644 index 0000000..9666a8f --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-3-report-1.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-diff-filter/test-PR25661-3-report-2.txt b/tests/data/test-diff-filter/test-PR25661-3-report-2.txt new file mode 100644 index 0000000..f275382 --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-3-report-2.txt @@ -0,0 +1,12 @@ +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 void foo(S*)' at test-PR25661-3-v1.c:21:1 has some indirect sub-type changes: + parameter 1 of type 'S*' has sub-type changes: + in pointed to type 'struct S' at test-PR25661-3-v1.c:1:1: + type size hasn't changed + data member 'S::a' was replaced by anonymous data member: + 'union {struct {struct {int a;};}; int new_union_member;}' + diff --git a/tests/data/test-diff-filter/test-PR25661-3-report-3.txt b/tests/data/test-diff-filter/test-PR25661-3-report-3.txt new file mode 100644 index 0000000..0927b7a --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-3-report-3.txt @@ -0,0 +1,5 @@ +Leaf changes summary: 0 artifact changed (1 filtered out) +Changed leaf types summary: 0 (1 filtered out) leaf type changed +Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function +Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable + diff --git a/tests/data/test-diff-filter/test-PR25661-3-report-4.txt b/tests/data/test-diff-filter/test-PR25661-3-report-4.txt new file mode 100644 index 0000000..bad754e --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-3-report-4.txt @@ -0,0 +1,9 @@ +Leaf changes summary: 1 artifact changed +Changed leaf types summary: 1 leaf type changed +Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function +Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable + +'struct S at test-PR25661-3-v0.c:1:1' changed: + type size hasn't changed + data member 'S::a' was replaced by anonymous data member: + 'union {struct {struct {int a;};}; int new_union_member;}' diff --git a/tests/data/test-diff-filter/test-PR25661-3-v0.c b/tests/data/test-diff-filter/test-PR25661-3-v0.c new file mode 100644 index 0000000..bd7a6df --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-3-v0.c @@ -0,0 +1,12 @@ + struct S +{ + int a; + int b; + int c; + int d; +}; + +void +foo(struct S* s __attribute__((unused))) +{ +} diff --git a/tests/data/test-diff-filter/test-PR25661-3-v0.o b/tests/data/test-diff-filter/test-PR25661-3-v0.o new file mode 100644 index 0000000000000000000000000000000000000000..269bfca7a6337d91fc8268a9518eb6483c0908da GIT binary patch literal 2760 zcmbtV&2Jk;6o2FKSF(xg#2^}l!yktPP*@e)qWUN zhhaNthy5TNR!xj51)Np8K@@1w>xR9a*9(V{nx-bZ_SQ{zyZ(|}ulY57L(LU3WK#jKV`@eZ%!e(Vel{>Z`Guh8@dYsyc=c)S8wGXkAZ@-#LKPWH)j zk4~}Y+Q>d1VOY{$QJ3ho-5YDv}u{_KNM6ts~?)0hufiqv5QK20C^?b!_csTu}; zSGDi-55jS8f;ue+?eCdl~up#kQ{ErAf8JzAFL3}syze3X%e(ji~_)}{E-Zz|?ZM%mG z8zbAmfHihB+_t5Crq$0w!TwY~y-s%hUBv8|2*CpbzD|n-*|rC$OUqv~L&<%j{Pb?v z`QJl~Vsf1*YWmG2`hfw%IY0A{5GUF8|JV$3(Bn&SE|R(O|kzl;GQX%-f8+*vHj^x?Ab#Inp6}Lzt{2V U;XQ{oeb%_v)pp z`rQ{^+D|YBYB0D83r(Q_U!@mvONcEf!#dnPxcBS9y?6e&|LS)?BAgVatcZ{ovNl4?;j&D)kELDO@2AEMY946O`OBlo-o?iI89b z?*LmBfs?!otR%!N?*UsAVjfodlL@em`6g9W?9(4GiZw&qDoKeChmg-wTI8~G#j?eV zTg5fDo++I{YnfTr73(?cvc<}{ivsX$q~0tyF=X;du&k>V$7)jrh_LjTB~FHL+z(QV ziVBb`GoIB$uQ=@5rV4(3lL}~^{rLJOrL|I8+QeCa{3@oUsPHsxfr^hBCM25FcISW; z_HpI#6wZwOSuEfzP6f7!LFmmw`|zmo?9NWzzG&aAJ6*v_F~~(Zh`hnxOK{{>hm)~a z?M-^G`PG3RR!4rv?f3)NA5~?HDg~TXdv53o(eC;EzTNjnp*M|9cH`ySmA(3;VMc z8|{<8p9Jl(H|}6cxUsi)rE&qYZ2!9y0FQ|VU~}F&0(M$rTlq}(J~r!d#OX&vwEFpC z>4U^xA-#_d5ga?yaZJMRf5jQGsc|s=UGwHI**RL`2A9{NDZhxsv%JDYUF2`DrLT(f~H4K>v{bZ){7P{Pq8RsNt0NbE$tVS2K>Pnc}3R4=p7roBo#{fmb9> zHR^SOGkbF!x*c4@X|xWN6ndv2ICM+F>C9%}Oudoo^t{f=pzR0!3EG70b~;nQ0($^3S7<&cT1>*O6<+q;x9(&!lL>^rg=MeVkjG4~f4- zUu<|FaXME7sWXe;6ft&jHe-_EoCLoWUW>`}Jw%gEarJ*DFNNY$ z{q$;?_4g1nVVj?ZE^X(m-$tnC_mk6GyfgLD5k0tMKO-$W&B0~a#i`& z`ZnTm{FFRUjep?3FZqTWTrv-&bWnMf|0j~a^mZWDl>DZ0l&jjmf$@H+^kPKK& + +struct S +{ + uint64_t marker[0]; + uint64_t a; + uint64_t b; + uint64_t c; +}; + +void +func(struct S *s) +{ + s->a = 1; +} diff --git a/tests/data/test-diff-filter/test-PR25661-4-v0.o b/tests/data/test-diff-filter/test-PR25661-4-v0.o new file mode 100644 index 0000000000000000000000000000000000000000..9362ec606da80b2cea9aba063c529d2bfdd62c4a GIT binary patch literal 3400 zcmb_e&2Jl35TCbe$D6KWoVb*v;jopc+DPo$4j~DxQbMCpM^q@JDu@HJ*7n+7YOjlT zT_r_)NK~j5LJAV%L*fKyBo3&83l|Rb1UHU|3x5E&3WQ+h?R)O#Wg{WPNPaW(o6q;T zerxmcvl?R{iNOVUph*q|YDs5XxSG zS*9D`p~!QvY@TGuxxgm!yIgDl%W=`jHGvsiEP_GCAMrOysR54B!1Ci|k8n zqOC}h_CXiqW%}y6ere2sYOtYC>@e#B>2BvudA)JR0ao(8|pcl@W=gp_gtr9j} z!j?@l1{eYpQwjU3iR~j`$N&Ni#-Wl{i!!womRoM* za?x)2?Y7#7&2kuQRh;BHTHsedrU$r)>D^|7QRGg}{ zSXr!8o>*M9&hFqGYHlP9HX5r7mfep=fw$K20&nOyQFVvS?%M9^vc0@y*&RUr8ur>A z1x<+8gLjxBI$2&4PZ`i+M(obEC`(Zllxvt;FO;p2cngjjq?i?zcMk&y7T}MZN_Zu zUl;mi1^-CsR}{P`j+Cq5?+d-H;3tKDq~N!OzNg@?34LF|Ga}DV3T_JgXMvNNTu-@o zv=02MCj5#=_;-)MErC<+WPWhMy?*32kVnIqccm10yAe3_{(;j7LvV&(&vjZ}W7Mhp zL3@BUF1wA!(7SQK><-)A7~zP(AvuNlquJRFuqqp7uzD;;1o)PsV~fnV~>M^8h-}ObRYg}d=+EWoK#WP zPy9tA_>eDsyy@T1I{uRMjW|^IL~=S;r*B35(@H_9O8z=}r^Wvw4%DK^Cz*_s{FaE9cFBu0sT7iN()1|`go$<~3^IOo zjKqSRzl1+TA#MHcrK}%)9c8>+*RRJne~k_Yi_l#Q8r-N`ln+ SQ{J@rUq%04Bw|Ta + +struct S +{ + union + { + uint64_t marker[0]; + struct + { + uint64_t a; + uint64_t b; + }; + }; + uint64_t c; +}; + +void +func(struct S *s) +{ + s->a = 1; +} diff --git a/tests/data/test-diff-filter/test-PR25661-4-v1.o b/tests/data/test-diff-filter/test-PR25661-4-v1.o new file mode 100644 index 0000000000000000000000000000000000000000..df219fc03e618fa9278605cb21f2227ac2200a94 GIT binary patch literal 3480 zcmb_ePiP}m82{c((@Z-}nl|fhyAjNS%eLT5l3Lrk(lu_W+r>p{mkJ6JC&?rkH<_%N z$KF6g^T1B*>OlOoNy6J z<(QHB0+~q%*mUjyIhd>iGdXKOI>%D_Hwg0VES)8O>K2(zlkpGuGbuK}%vD%my73#b z8Hxy#4PeBypE92`FXwSdd1jiC$WWZjfNn_bh6#{9HKsREAM>8d00o(5 z>~fym%`+&kquWd#7Z(qlAxjFFwb|2)GRC<@Dz>`t@x?`QpH0QGYYVs)v$zDx0FU8M zqlHF$%Q+h4){Fqb+{9UjmvCh4uWSZKej{vue*WWp(_}KO}r=85C=a(AjM!RDv5H(!mQ*LJ*aNmNmyl7dpx2_4Q_O|R9mT3$DF z2hi>NZ6!LUSX-@yi7OeUZgiXh@PS95vP6X(y!8BjajUXktd#AtT`8`VSIXtbS2l`E zd$@)jClm?`m6he9)eDEdyV-Vqci=TpbOw#i=E26AwYFNc+JN#kthF`t8xZXW<*U_b z3wfz03zaS5|7|GSiQBuFQs3E0g&UW)6+6oxeNh325POJHvK%}{70*TWTCZhaA z5-)NIU{TC;Lh;jB7C70*&%GSODenhDURQ7-;#VsonU~rS(RMVA>Zu9&ih_SB}VhOS5nyJ9$?>j z0A3V0#g4}ZJ2>oxP95iP5X~LQh3-KJHg!R;>p=ka!0kGA)2$ENHP3JLQO9|wULUwO z#?;Qh@!RgWOV{&V>4GW1ZuEOS7u%BU_e0mlR%8XC)3_!Axt&^T;PmLz|36RxW6<8p z{gffAf*HLlA&X;?W^e{M!qg7);>cp0QT@-Mn%={I^{=3>8j~{0{EsL~MdY7w`ZrZ2 zrx+PxL%tUdbg#%xzFqtuz-bdlH6|&B0{oeT7^$|qs8caA-xrrr_6He4wS5j1N%j9I zTDA12`Uz6&Zz86~L + +struct S +{ + int a; + int b; + int c; +};// end struct S + +void +func(struct S *s) +{ + s->a = 1; +} diff --git a/tests/data/test-diff-filter/test-PR25661-5-v0.o b/tests/data/test-diff-filter/test-PR25661-5-v0.o new file mode 100644 index 0000000000000000000000000000000000000000..332f35dac2ec19817f452a49b06504bb12c8c01a GIT binary patch literal 3152 zcmbtW&2Jl35TCc}jkn#zI5CKZaM&VH8x*fUplMo^5{N=mQ9+a{;sjxBuk8hU4eL!6 zKnTQ_sJH}yL_tUh_1rsmgy6sdiN67fE4NBLz|7lu&ib)P2%h9OGr#$K^FG$^Y+ZfE z5CYT?a0!kjg#sKEkNFMBZa@VVU~l`zZ`(KCzO((w)}0@v=h2Jb|AYnwX=KY-vy#tD z_hooP*d!T-%wQB!Vy8sRq&ka;S+K$=0mGJ(k?IQ9U{;v+m#DXV5LWR8GPPPDW+Yp% z+8~OOwLwM`&SZhA4)OI5=u{koaLU9PpZ3AF2NX%ni$_Wo$1E+C=EXv>d_QU*2FJOC z5SGL&E}>AtG92fk^MrH35f!Xq4oo{0uT<6?fEiCbxoDPB=*%L8+c@>b(~D$Wv@*uV zDFFK(OmYP^utEh&U?&Bl4RQTOUz!)?}^_4;GYHTUc;mcH#Ltf->0vFuid$w3sX_kt*h!#0Y3-0rU* zuB}#AA9t%g=pICENY_t^;PU3?MfWV`SpIhju$TAB_G0Vb+y!x17E7~5`v|wl>fBc!J#NEn+@i0ubc1mxeCU2O0d3Bwc-X9&tD4EA0 zqc!0~MmlCqz{`*`Oqk0-=`iC>%NZv8?O~C|MqenbHnrcVn4xvd`{&J%dyH4_Q91;Vj~-oeq_k9u68? zDVfx{&+=6b|CZ%z8m?ODYxqr;`x^ck%U@~uU6xfIy$`DARKLZxM9R$T_80yEcNwQ1 zXZsA^_>E!Ww~!`rO8bgSg2MzndY-^*jmO}{!NB)ALF=HmA4c5~>Ll;CT5)iFO6|vf z)C;Cv24NH^7fbB! z1HilNKoG}jn!)#^)$yd;?x0G?$odw8>Rzh|x-EUY^XmVYH&ppk z{q*YU^>+}{VKz_36-em zTWFo{hf-!@jyx@v%Y?co9oZ@-rX literal 0 HcmV?d00001 diff --git a/tests/data/test-diff-filter/test-PR25661-5-v1.c b/tests/data/test-diff-filter/test-PR25661-5-v1.c new file mode 100644 index 0000000..7f0eb6e --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-5-v1.c @@ -0,0 +1,25 @@ +#include + +struct S +{ + struct + { + union + { + int a; + char a_1; + }; + union + { + int b; + char b_1; + }; + }; + int c; +}; // end struct S + +void +func(struct S *s) +{ + s->a = 1; +} diff --git a/tests/data/test-diff-filter/test-PR25661-5-v1.o b/tests/data/test-diff-filter/test-PR25661-5-v1.o new file mode 100644 index 0000000000000000000000000000000000000000..1d32777cc2733aa0c62652eaad9039ca4f0d2e0e GIT binary patch literal 3280 zcmbtW-HRJl6hC(+vzhE<)9gmuT~}}frCo6*AKGnN*&1EeZn4;~W${UtNis=BlZj+z z%c_WqQY;Eq5JV6~eDOiw`>YTC55CwJ@!7XRAM~6%_hu)zQxH9nx##@O=RNl;@9kW9 zNn;EoF}MiFl0*T@<}u&mYzr!|0{go+|Jc3x?%mx_cJBVlJ#W4CO9><7xRJ?Y6_0%r z?%@=mF&HeNU>GTr>05ORh>7uZUkqMNWt06RHr zlbj9v+Ct2VP*)~S`+NvRlVSr~W>1zXmR?#fEn}SWDbzjzmUR&!oS0y-5xG;$vMyN9 zS?4WQ!J?NyHxuzPiVKxFZGH(ZSDF^qRKa4?eucCjSuDEj`8B39UgPZM zX5BgKT(7%bash)uA<2P)ev%pHhX(sr)6qE^PNuPa7)HS$^m{g~{+v)9PR4$LdoaeNs1TLVAzr$HA* zZ`vJh9W^(d&1Y?A0R6+T3(5Q`5nS5dzF?oh92@^G0dFn9Lt}xf(G`!!Uw>yQamBJ=+z_+nozv^6$s%1`9;!|UejBJT zM&Xx5241)iBR~f{5E-PyQU*%)ct$fwhvI!G^>QWEhuJ~N+WmZulMr%dbhk*JG%^F> zG@G9YL|RS;eispbAY_?O+S>wO6C zl3`ZoXF|TB;NJ=Pnu5z#dJ29+$U_DHK*)C#{GO2i6rkF&KQF?r`~ds&55R4K zQ;*Yq1~+DE>2?;)nfLC_mjxYW_D7qnNTzWI25!@-He0 zr6|XD&^pWi2eF|VBAy(ipBz6D{!%Z;-_#8$6w*)HeT58RqFf2X9pT@cAqgYrFX1nc z$?9J_qkr_ONq^bbtlSiPm4YI*MZxs`&}*ss)0$*Wbtv}#BdAZ4I)93r=`ZU4KJARW G>i-W$y!Chh literal 0 HcmV?d00001 diff --git a/tests/data/test-diff-filter/test-PR25661-6-report-1.txt b/tests/data/test-diff-filter/test-PR25661-6-report-1.txt new file mode 100644 index 0000000..9666a8f --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-6-report-1.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-diff-filter/test-PR25661-6-report-2.txt b/tests/data/test-diff-filter/test-PR25661-6-report-2.txt new file mode 100644 index 0000000..0927b7a --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-6-report-2.txt @@ -0,0 +1,5 @@ +Leaf changes summary: 0 artifact changed (1 filtered out) +Changed leaf types summary: 0 (1 filtered out) leaf type changed +Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function +Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable + diff --git a/tests/data/test-diff-filter/test-PR25661-6-report-3.txt b/tests/data/test-diff-filter/test-PR25661-6-report-3.txt new file mode 100644 index 0000000..e0044f6 --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-6-report-3.txt @@ -0,0 +1,12 @@ +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 void foo(S*)' at test-v1.c:11:1 has some indirect sub-type changes: + parameter 1 of type 'S*' has sub-type changes: + in pointed to type 'struct S' at test-v1.c:1:1: + type size hasn't changed + data member 'S::a' was replaced by anonymous data member: + 'union {int a; char added;}' + diff --git a/tests/data/test-diff-filter/test-PR25661-6-report-4.txt b/tests/data/test-diff-filter/test-PR25661-6-report-4.txt new file mode 100644 index 0000000..a3f4c72 --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-6-report-4.txt @@ -0,0 +1,9 @@ +Leaf changes summary: 1 artifact changed +Changed leaf types summary: 1 leaf type changed +Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function +Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable + +'struct S at test-v0.c:1:1' changed: + type size hasn't changed + data member 'S::a' was replaced by anonymous data member: + 'union {int a; char added;}' diff --git a/tests/data/test-diff-filter/test-PR25661-6-v0.c b/tests/data/test-diff-filter/test-PR25661-6-v0.c new file mode 100644 index 0000000..4c93e56 --- /dev/null +++ b/tests/data/test-diff-filter/test-PR25661-6-v0.c @@ -0,0 +1,10 @@ +struct S +{ + int a; +}; + +void +foo(struct S *s) +{ + s->a = 1; +} diff --git a/tests/data/test-diff-filter/test-PR25661-6-v0.o b/tests/data/test-diff-filter/test-PR25661-6-v0.o new file mode 100644 index 0000000000000000000000000000000000000000..ec1797da0d1daa3c1deb9d0be5af339154db6e6b GIT binary patch literal 2656 zcmbtV&ubGw6n>L!n$)#1Z4?dlu!7PS%%(p>Td78i+M;Nw7Q9H=B->=QNlLOURS^%0 zP`p$SR1g%ri2sHMJ^45E;$3eA5BlEhOgfovDd>aDy!XBLz4vBzX7c3n^(zs^KnjEN zuxm*a;6rp*&vP{oDd>g8+07rbn~!&9UtHe#%9(e+tfRk!$HaN6J^7AuXD~!=K?h@( z&@dce1}Vtyh2fPR3kn!o)(S!8FgCMjRk&vkU3K*PkYK{>1A`Y2tK7Tb#%V zfY=e_%pneEsXEmK*=o|w*VPc3=tNRS-)FEyg&^nrJegnGNY-t#PCoV(`=ng@t|HMA{;XOEI z?p5|d?!R)b=rXldatPzqRmqHmQ}^TeBk2hykhn16n1+*|Bppn=lhzSNY*647r+(-8 zed1+r6t6rzklZJpUw`z`IZ^9cBAzf62fO*8>N^FT{YEfXq~^ODKG-G4cfc+*n_xHG z6~`{Qg|+gMS6i;5kLymM&~Vq=+)l%(mECsAidSZ!5=J0KJ`zpk=}m^v9S780n++Z(PNj;8CL(Bs4w@4>eIWS z*Iz}9a>_nYk+dMp7k%ldMDgm@UgUtDJU0RA(<*TP`2?J?N(%DNJHEBJc&9RW

PN3lxwiy3FB+zIn*K#}K7AAY?jZ!*0z5*7BKrC% QZy0|^^#4)elB)Cn0^_%a = 1; +} diff --git a/tests/data/test-diff-filter/test-PR25661-6-v1.o b/tests/data/test-diff-filter/test-PR25661-6-v1.o new file mode 100644 index 0000000000000000000000000000000000000000..21a6a89e89dddeda3b3fea16180c78fce773952f GIT binary patch literal 2792 zcmbtV&2Jk;6o2FOSF*L6#8hn*4vPe8BGv08Z7jD{T0>Oo0xD_RN?fXF?cLZ5u^p|q zRRAF>wL(N(Kp+qw5(n;xD`yV;3;Y8}oRGLh;?TY~JI@|ZSE>Xf?Y#GX?{hxh?8n#M zdOafq@DOkXCK96n%lQf4lx!0!umE>kM}M}CK00oFcJ26g>3Q$BuTh_sHboignRqWq zWin;5!g>Q)%L9=kMtX|;EmG&Qxo{9eUdZf)+mIC^M7&rfEzIl!EdvxP!YWSOizT>GX<$7wuDH6GL^``jnVM(5d2Nw0%;v@!GG_qnlNgqg z!8xjwY6MK74PKN6N%k_%8E|kG;@@%!XL*Xa*8<{T6jvXtxgBWP&Yt z3;#SxQ(CE=fV-#;%Ji{NlQt~X4W`Zlt*JDn1qDr-uolcr1dX#`+yWX(b(W@N7A(N4 zn=&jo@eE3l7qorg{nw71nsB_5S+v(z#Ssao>RC6BJPpQgCL)|tl<|8?UR0FMYkZxN zUr{*O>*st`!}VReW8m^xKQ)(~r2HjxVWj`DQ z?1Cx4?F{?<0H0TPFpL8iTd+Ecz0P|oP|(}mi@biI3jd#E3H@nLct1H@Q!(RvrDU?z z$4e*>W_B2#r*2EU>3N&(_pzh;1c5O87(Jbgu~F zyNv$`IW}=NW0K-;sRj66Q6{GCHY!YvY>yPU%8rVfwr?VyR==Z~g8iv}dcDm0eZ9Q?`43b~t`kK$j#Z*h8Bmn-GyM>8;!XdDs+ryA z_&-+uh8g@k^%zXFoR^VrmA`5Jivk*Ks3@91q@)0vpPhY&QVC>$pfGM>%#Q`|KFhpPUc#-0gd`acEuEVPsW literal 0 HcmV?d00001 diff --git a/tests/test-diff-filter.cc b/tests/test-diff-filter.cc index 215485b..3ddbdbc 100644 --- a/tests/test-diff-filter.cc +++ b/tests/test-diff-filter.cc @@ -570,6 +570,174 @@ InOutSpec in_out_specs[] = "data/test-diff-filter/PR24787-report-0.txt", "output/test-diff-filter/PR24787-report-0.txt", }, + { + "data/test-diff-filter/test-PR25661-1-v0.o", + "data/test-diff-filter/test-PR25661-1-v1.o", + "--no-default-suppression", + "data/test-diff-filter/test-PR25661-1-report-1.txt", + "output/test-diff-filter/test-PR25661-1-report-1.txt", + }, + { + "data/test-diff-filter/test-PR25661-1-v0.o", + "data/test-diff-filter/test-PR25661-1-v1.o", + "--no-default-suppression --harmless", + "data/test-diff-filter/test-PR25661-1-report-2.txt", + "output/test-diff-filter/test-PR25661-1-report-2.txt", + }, + { + "data/test-diff-filter/test-PR25661-1-v0.o", + "data/test-diff-filter/test-PR25661-1-v1.o", + "--no-default-suppression --leaf-changes-only", + "data/test-diff-filter/test-PR25661-1-report-3.txt", + "output/test-diff-filter/test-PR25661-1-report-3.txt", + }, + { + "data/test-diff-filter/test-PR25661-1-v0.o", + "data/test-diff-filter/test-PR25661-1-v1.o", + "--no-default-suppression --harmless --leaf-changes-only", + "data/test-diff-filter/test-PR25661-1-report-4.txt", + "output/test-diff-filter/test-PR25661-1-report-4.txt", + }, + { + "data/test-diff-filter/test-PR25661-2-v0.o", + "data/test-diff-filter/test-PR25661-2-v1.o", + "--no-default-suppression", + "data/test-diff-filter/test-PR25661-2-report-1.txt", + "output/test-diff-filter/test-PR25661-2-report-1.txt", + }, + { + "data/test-diff-filter/test-PR25661-2-v0.o", + "data/test-diff-filter/test-PR25661-2-v1.o", + "--no-default-suppression --harmless", + "data/test-diff-filter/test-PR25661-2-report-2.txt", + "output/test-diff-filter/test-PR25661-2-report-2.txt", + }, + { + "data/test-diff-filter/test-PR25661-2-v0.o", + "data/test-diff-filter/test-PR25661-2-v1.o", + "--no-default-suppression --leaf-changes-only", + "data/test-diff-filter/test-PR25661-2-report-3.txt", + "output/test-diff-filter/test-PR25661-2-report-3.txt", + }, + { + "data/test-diff-filter/test-PR25661-2-v0.o", + "data/test-diff-filter/test-PR25661-2-v1.o", + "--no-default-suppression --harmless --leaf-changes-only", + "data/test-diff-filter/test-PR25661-2-report-4.txt", + "output/test-diff-filter/test-PR25661-2-report-4.txt", + }, + { + "data/test-diff-filter/test-PR25661-3-v0.o", + "data/test-diff-filter/test-PR25661-3-v1.o", + "--no-default-suppression", + "data/test-diff-filter/test-PR25661-3-report-1.txt", + "output/test-diff-filter/test-PR25661-3-report-1.txt", + }, + { + "data/test-diff-filter/test-PR25661-3-v0.o", + "data/test-diff-filter/test-PR25661-3-v1.o", + "--no-default-suppression --harmless", + "data/test-diff-filter/test-PR25661-3-report-2.txt", + "output/test-diff-filter/test-PR25661-3-report-2.txt", + }, + { + "data/test-diff-filter/test-PR25661-3-v0.o", + "data/test-diff-filter/test-PR25661-3-v1.o", + "--no-default-suppression --leaf-changes-only", + "data/test-diff-filter/test-PR25661-3-report-3.txt", + "output/test-diff-filter/test-PR25661-3-report-3.txt", + }, + { + "data/test-diff-filter/test-PR25661-3-v0.o", + "data/test-diff-filter/test-PR25661-3-v1.o", + "--no-default-suppression --harmless --leaf-changes-only", + "data/test-diff-filter/test-PR25661-3-report-4.txt", + "output/test-diff-filter/test-PR25661-3-report-4.txt", + }, + { + "data/test-diff-filter/test-PR25661-4-v0.o", + "data/test-diff-filter/test-PR25661-4-v1.o", + "--no-default-suppression", + "data/test-diff-filter/test-PR25661-4-report-1.txt", + "output/test-diff-filter/test-PR25661-4-report-1.txt", + }, + { + "data/test-diff-filter/test-PR25661-4-v0.o", + "data/test-diff-filter/test-PR25661-4-v1.o", + "--no-default-suppression --harmless", + "data/test-diff-filter/test-PR25661-4-report-2.txt", + "output/test-diff-filter/test-PR25661-4-report-2.txt", + }, + { + "data/test-diff-filter/test-PR25661-4-v0.o", + "data/test-diff-filter/test-PR25661-4-v1.o", + "--no-default-suppression --leaf-changes-only", + "data/test-diff-filter/test-PR25661-4-report-3.txt", + "output/test-diff-filter/test-PR25661-4-report-3.txt", + }, + { + "data/test-diff-filter/test-PR25661-4-v0.o", + "data/test-diff-filter/test-PR25661-4-v1.o", + "--no-default-suppression --harmless --leaf-changes-only", + "data/test-diff-filter/test-PR25661-4-report-4.txt", + "output/test-diff-filter/test-PR25661-4-report-4.txt", + }, + { + "data/test-diff-filter/test-PR25661-5-v0.o", + "data/test-diff-filter/test-PR25661-5-v1.o", + "--no-default-suppression", + "data/test-diff-filter/test-PR25661-5-report-1.txt", + "output/test-diff-filter/test-PR25661-5-report-1.txt", + }, + { + "data/test-diff-filter/test-PR25661-5-v0.o", + "data/test-diff-filter/test-PR25661-5-v1.o", + "--no-default-suppression --harmless", + "data/test-diff-filter/test-PR25661-5-report-2.txt", + "output/test-diff-filter/test-PR25661-5-report-2.txt", + }, + { + "data/test-diff-filter/test-PR25661-5-v0.o", + "data/test-diff-filter/test-PR25661-5-v1.o", + "--no-default-suppression --leaf-changes-only", + "data/test-diff-filter/test-PR25661-5-report-3.txt", + "output/test-diff-filter/test-PR25661-5-report-3.txt", + }, + { + "data/test-diff-filter/test-PR25661-5-v0.o", + "data/test-diff-filter/test-PR25661-5-v1.o", + "--no-default-suppression --harmless --leaf-changes-only", + "data/test-diff-filter/test-PR25661-5-report-4.txt", + "output/test-diff-filter/test-PR25661-5-report-4.txt", + }, + { + "data/test-diff-filter/test-PR25661-6-v0.o", + "data/test-diff-filter/test-PR25661-6-v1.o", + "--no-default-suppression", + "data/test-diff-filter/test-PR25661-6-report-1.txt", + "output/test-diff-filter/test-PR25661-6-report-1.txt", + }, + { + "data/test-diff-filter/test-PR25661-6-v0.o", + "data/test-diff-filter/test-PR25661-6-v1.o", + "--no-default-suppression --leaf-changes-only", + "data/test-diff-filter/test-PR25661-6-report-2.txt", + "output/test-diff-filter/test-PR25661-6-report-2.txt", + }, + { + "data/test-diff-filter/test-PR25661-6-v0.o", + "data/test-diff-filter/test-PR25661-6-v1.o", + "--no-default-suppression --harmless", + "data/test-diff-filter/test-PR25661-6-report-3.txt", + "output/test-diff-filter/test-PR25661-6-report-3.txt", + }, + { + "data/test-diff-filter/test-PR25661-6-v0.o", + "data/test-diff-filter/test-PR25661-6-v1.o", + "--no-default-suppression --harmless --leaf-changes-only", + "data/test-diff-filter/test-PR25661-6-report-4.txt", + "output/test-diff-filter/test-PR25661-6-report-4.txt", + }, // This should be the last entry {NULL, NULL, NULL, NULL, NULL} };