Message ID | 20200610115940.26035-7-gprocida@google.com |
---|---|
State | Committed |
Headers |
Return-Path: <libabigail-bounces@sourceware.org> 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 515F3388C019; Wed, 10 Jun 2020 11:59:59 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 515F3388C019 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1591790399; bh=bIUGi5q0CDSaZMZltJ81lv3s0hPE0lH1E8XZymIPlXM=; h=Date:In-Reply-To:References:Subject:To:List-Id:List-Unsubscribe: List-Archive:List-Help:List-Subscribe:From:Reply-To:Cc:From; b=HiOVz+id/QLIZLZy6JPcoe/mapUi8hiOBVPCczXSITKE1LnkuqXbndCr7X5M79LTN yP7aZW/S/kvm2Lo772xFdLtnVwFim7hNzhai2D1JgLK+VQXy001DyRiJS4i5COlpH6 k5np2pX0FevgSVqkRIKNDHbE5p54t5JsAHj2glNE= X-Original-To: libabigail@sourceware.org Delivered-To: libabigail@sourceware.org Received: from mail-qt1-x84a.google.com (mail-qt1-x84a.google.com [IPv6:2607:f8b0:4864:20::84a]) by sourceware.org (Postfix) with ESMTPS id CE34D388C00E for <libabigail@sourceware.org>; Wed, 10 Jun 2020 11:59:56 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org CE34D388C00E Received: by mail-qt1-x84a.google.com with SMTP id u26so1591452qtj.21 for <libabigail@sourceware.org>; Wed, 10 Jun 2020 04:59:56 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=bIUGi5q0CDSaZMZltJ81lv3s0hPE0lH1E8XZymIPlXM=; b=KStc+B9CqbF7W97anhL22MrwB6saXembKeVf7CLK9m6UGVEfwZaH2BoXc9xVYOAR/0 erbU1T24sC6KGyht2cyf8XoO1f0hez31b5MSwyvpDlahNUTcMDbLfw/AFPBJ/Lbx9jB2 bMg6inikzZwPh8zlwebnYbUhpGUFAqi1pe6GvRf6EuA8rsUcdx6FKmFnx3scRpcmeH4a umCBRukQ15QomJhpIPYZw1CAJqdD7rl87Cajiai6lH5Ok8N1YMZ804MEBZq4WeGk+ptQ cZO1GhHJLD3r7aWY7pWd3b8y3rM4upj8hHmB6NJQA36yBaj/7hnI7gefH59hkE3T7zNP iJww== X-Gm-Message-State: AOAM531NPI2RB77UdlXCzaSHfxnc+GdWzi+hxbmw6SVo+SfyPn/pqVPG S8MWie6Ws3lR4dXak3L0npMTRHmAFv5FRE8mGzffiyz09/v3RP25/OwIdIezbGsUR9roOrRzVl2 1cHFGiGCi6SoJEGI59Qu+QX77v3JzTq1BOOu5R1pJLO3G6qkHgREsnrVPAjBsAX00uoefz+Q= X-Google-Smtp-Source: ABdhPJzoT1j3MeAnhUxqqj3x1plAE0TtRPkqigIv5sqMbF7ycBQDsOxVMoQAxHM8DRTLcfp0p+R+4CV0X9Z7+A== X-Received: by 2002:a05:6214:10e1:: with SMTP id q1mr2594585qvt.78.1591790396226; Wed, 10 Jun 2020 04:59:56 -0700 (PDT) Date: Wed, 10 Jun 2020 12:59:35 +0100 In-Reply-To: <20200610115940.26035-1-gprocida@google.com> Message-Id: <20200610115940.26035-7-gprocida@google.com> Mime-Version: 1.0 References: <20200610115940.26035-1-gprocida@google.com> X-Mailer: git-send-email 2.27.0.278.ge193c7cf3a9-goog Subject: [PATCH 06/11] Support incomplete enums in core and diff code. To: libabigail@sourceware.org Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-23.5 required=5.0 tests=BAYES_00, DKIMWL_WL_MED, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, USER_IN_DEF_DKIM_WL 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 <libabigail.sourceware.org> List-Unsubscribe: <http://sourceware.org/mailman/options/libabigail>, <mailto:libabigail-request@sourceware.org?subject=unsubscribe> List-Archive: <https://sourceware.org/pipermail/libabigail/> List-Help: <mailto:libabigail-request@sourceware.org?subject=help> List-Subscribe: <http://sourceware.org/mailman/listinfo/libabigail>, <mailto:libabigail-request@sourceware.org?subject=subscribe> From: Giuliano Procida via Libabigail <libabigail@sourceware.org> Reply-To: Giuliano Procida <gprocida@google.com> Cc: kernel-team@android.com, gprocida@google.com Errors-To: libabigail-bounces@sourceware.org Sender: "Libabigail" <libabigail-bounces@sourceware.org> |
Series |
Add incomplete enum support.
|
|
Commit Message
Giuliano Procida
June 10, 2020, 11:59 a.m. UTC
This is an almost blind attempt at addition of support for incomplete,
also known as forward-declared, enum types. I've not made any attempt
to refactor or share logic with the struct/union code and I've
probably got other things wrong.
This patch:
- adds enums_type and enum_type_decl_wptr typedefs
- adds declaration-only machinery to enum_type_decl
- adds is_compatible_with_enum_type, look_through_decl_only_class,
there_is_a_decl_only_enum and lookup_enum_type helpers
- adds has_enum_decl_only_def_change functions
- inserts has_enum_decl_only_def_change wherever
has_class_decl_only_def_change is present
- adds reporting of enum declaration/definition diffs
- doesn't address the DWARF reader, XML writer or XML reader
Signed-off-by: Giuliano Procida <gprocida@google.com>
---
include/abg-comp-filter.h | 7 ++
include/abg-fwd.h | 24 +++++
include/abg-ir.h | 15 +++
src/abg-comp-filter.cc | 74 +++++++++++++-
src/abg-comparison.cc | 4 +-
src/abg-default-reporter.cc | 19 ++++
src/abg-ir.cc | 196 +++++++++++++++++++++++++++++++++++-
7 files changed, 333 insertions(+), 6 deletions(-)
Comments
Hello, Giuliano Procida <gprocida@google.com> a écrit: > This is an almost blind attempt at addition of support for incomplete, > also known as forward-declared, enum types. I've not made any attempt > to refactor or share logic with the struct/union code and I've > probably got other things wrong. > > This patch: > > - adds enums_type and enum_type_decl_wptr typedefs > - adds declaration-only machinery to enum_type_decl > - adds is_compatible_with_enum_type, look_through_decl_only_class, > there_is_a_decl_only_enum and lookup_enum_type helpers > - adds has_enum_decl_only_def_change functions > - inserts has_enum_decl_only_def_change wherever > has_class_decl_only_def_change is present > - adds reporting of enum declaration/definition diffs > - doesn't address the DWARF reader, XML writer or XML reader So, I have amended this patch to make it so that declaration-only-ness becomes a property of any declaration. Namely, it becomes a property of abigail::ir::decl_base. Besides the obvious code sharing advantage, it allows the underlying type of enums to also be flagged as decl-only whenever an enum is decl-only. Thus, when the underlying type of an enum changes from decl-only to defined that change is filtered out from the leaf reporter, as it is for class, unions and now enums. I have also added a ChangeLog to the commit log of the patch. You'll find the amended patch below, but you can also get it from the branch dodji/incomp-enums, browsable online at https://sourceware.org/git/?p=libabigail.git;a=shortlog;h=refs/heads/dodji/incomp-enums. From 7dd6e05d28d2f023e6b2158cd517c0b6db8eec5d Mon Sep 17 00:00:00 2001 From: Giuliano Procida <gprocida@google.com> Date: Wed, 10 Jun 2020 12:59:35 +0100 Subject: [PATCH 1/4] Support incomplete enums in core and diff code. This is an initial implementation of the support for incomplete, also known as forward-declared, enum types. I've not made any attempt to refactor or share logic with the struct/union code. * include/abg-comp-filter.h (has_decl_only_def_change) : Declare New function. * src/abg-comp-filter.cc (there_is_a_decl_only_enum): Define new static function and ... (type_size_changed): ... use it here. (has_decl_only_def_change): Define new function and ... (categorize_harm{less, ful}_diff_node): ... use it here. * include/abg-fwd.h (enums_type, decl_base_wptr): Declare new typedefs. (look_through_decl_only_class): Declare new overload for class_or_union*. (is_compatible_with_enum_type, is_compatible_with_enum_type) (look_through_decl_only, lookup_enum_types, lookup_enum_types): Declare new functions. * include/abg-ir.h (decl_base::{get_is_declaration_only, set_is_declaration_only, set_definition_of_declaration, get_definition_of_declaration, get_naked_definition_of_declaration}): Declare new member functions. They were moved here from the class_or_union class. (class_or_union::{get_earlier_declaration, set_earlier_declaration, get_definition_of_declaration, set_definition_of_declaration, get_naked_definition_of_declaration, get_is_declaration_only, set_is_declaration_only}): Remove these member functions. * src/abg-ir.cc (decl_base::priv::{declaration_, definition_of_declaration_, naked_definition_of_declaration_, is_declaration_only_}): Define data members. Moved here from class_or_union. (decl_base::priv::priv): Adjust to initialize the new data members. (decl_base::{get_earlier_declaration, set_earlier_declaration, get_definition_of_declaration, get_naked_definition_of_declaration, get_is_declaration_only, set_is_declaration_only, set_definition_of_declaration}): Define member functions. (operator|): In the overload for (change_kind, change_kind), adjust the return type of the call to decl_base::get_definition_of_declaration. (look_through_decl_only): Define new function. (look_through_decl_only_class): Adjust. (look_through_decl_only_enum): Likewise. (maybe_update_types_lookup_map<class_decl>): Adjust return type of call to decl_base::get_definition_of_declaration. (types_defined_same_linux_kernel_corpus_public): Use look_through_decl_only_class rather than open coding it. (class_or_union::priv::{declaration_, definition_of_declaration_, naked_definition_of_declaration_, is_declaration_only_}): Remove these data members. They are now carried by decl_base::priv. (class_or_union::{g,s}et_alignment_in_bits): Adjust. (class_or_union::{g,s}et_size_in_bits): Likewise. (class_or_union::operator==): Likewise. (equals): Adjust the overload for class_or_union. (is_compatible_with_enum_type) * src/abg-comparison.cc (try_to_diff<class_decl>): Adjust the return type of decl_base::get_definition_of_declaration. (leaf_diff_node_marker_visitor::visit_begin): Use filtering::has_decl_only_def_change rather than filtering::has_class_decl_only_def_change. Decl-only changes to enums (or any other type really) will thus not be recorded as leaf changes. * src/abg-dwarf-reader.cc (get_scope_for_die): Adjust return type of decl_base::get_definition_of_declaration. * src/abg-default-reporter.cc (default_reporter::report): Report enum decl-only <-> definition changes. * src/abg-hash.cc (class_or_union::hash::operator()): In the overload for class_or_union& adjust the return type for decl_base::get_definition_of_declaration. Signed-off-by: Giuliano Procida <gprocida@google.com> Signed-off-by: Dodji Seketeli <dodji@redhat.com> --- include/abg-comp-filter.h | 14 ++ include/abg-fwd.h | 36 ++++ include/abg-ir.h | 48 ++--- src/abg-comp-filter.cc | 131 ++++++++++++- src/abg-comparison.cc | 10 +- src/abg-default-reporter.cc | 19 ++ src/abg-dwarf-reader.cc | 3 +- src/abg-hash.cc | 3 +- src/abg-ir.cc | 456 +++++++++++++++++++++++++++----------------- 9 files changed, 509 insertions(+), 211 deletions(-) diff --git a/include/abg-comp-filter.h b/include/abg-comp-filter.h index 8113003..556bad4 100644 --- a/include/abg-comp-filter.h +++ b/include/abg-comp-filter.h @@ -65,13 +65,27 @@ bool is_decl_only_class_with_size_change(const diff *diff); bool +has_decl_only_def_change(const decl_base_sptr& first, + const decl_base_sptr& second); + +bool +has_decl_only_def_change(const diff *d); + +bool has_class_decl_only_def_change(const class_or_union_sptr& first, const class_or_union_sptr& second); bool +has_enum_decl_only_def_change(const enum_type_decl_sptr& first, + const enum_type_decl_sptr& second); + +bool has_class_decl_only_def_change(const diff *diff); bool +has_enum_decl_only_def_change(const diff *diff); + +bool has_basic_type_name_change(const diff *); bool diff --git a/include/abg-fwd.h b/include/abg-fwd.h index 999b071..7a85db3 100644 --- a/include/abg-fwd.h +++ b/include/abg-fwd.h @@ -155,6 +155,12 @@ class enum_type_decl; /// Convenience typedef for shared pointer to a @ref enum_type_decl. typedef shared_ptr<enum_type_decl> enum_type_decl_sptr; +/// Convenience typedef for a vector of @ref enum_type_decl_sptr +typedef vector<enum_type_decl_sptr> enums_type; + +/// Convenience typedef for a weak pointer to a @ref decl_base. +typedef weak_ptr<decl_base> decl_base_wptr; + class class_or_union; typedef shared_ptr<class_or_union> class_or_union_sptr; @@ -424,6 +430,12 @@ typedef_decl* is_typedef(type_base*); enum_type_decl_sptr +is_compatible_with_enum_type(const type_base_sptr&); + +enum_type_decl_sptr +is_compatible_with_enum_type(const decl_base_sptr&); + +enum_type_decl_sptr is_enum_type(const type_or_decl_base_sptr&); const enum_type_decl* @@ -513,6 +525,24 @@ look_through_decl_only_class(const class_or_union&); class_or_union_sptr look_through_decl_only_class(class_or_union_sptr); +class_or_union* +look_through_decl_only_class(class_or_union*); + +enum_type_decl_sptr +look_through_decl_only_enum(const enum_type_decl&); + +enum_type_decl_sptr +look_through_decl_only_enum(enum_type_decl_sptr); + +decl_base_sptr +look_through_decl_only(const decl_base&); + +decl_base* +look_through_decl_only(decl_base*); + +decl_base_sptr +look_through_decl_only(const decl_base_sptr&); + var_decl* is_var_decl(const type_or_decl_base*); @@ -1085,6 +1115,12 @@ lookup_enum_type(const string&, const corpus&); enum_type_decl_sptr lookup_enum_type(const interned_string&, const corpus&); +const type_base_wptrs_type* +lookup_enum_types(const interned_string&, const corpus&); + +const type_base_wptrs_type* +lookup_enum_types(const string&, const corpus&); + enum_type_decl_sptr lookup_enum_type_per_location(const interned_string&, const corpus&); diff --git a/include/abg-ir.h b/include/abg-ir.h index d81de21..468198c 100644 --- a/include/abg-ir.h +++ b/include/abg-ir.h @@ -1553,6 +1553,27 @@ public: void set_visibility(visibility v); + const decl_base_sptr + get_earlier_declaration() const; + + void + set_earlier_declaration(const decl_base_sptr&); + + const decl_base_sptr + get_definition_of_declaration() const; + + void + set_definition_of_declaration(const decl_base_sptr&); + + const decl_base* + get_naked_definition_of_declaration() const; + + bool + get_is_declaration_only() const; + + void + set_is_declaration_only(bool f); + friend type_base_sptr canonicalize(type_base_sptr); @@ -3781,27 +3802,6 @@ public: void set_naming_typedef(const typedef_decl_sptr&); - bool - get_is_declaration_only() const; - - void - set_is_declaration_only(bool f); - - void - set_definition_of_declaration(class_or_union_sptr); - - const class_or_union_sptr - get_definition_of_declaration() const; - - const class_or_union* - get_naked_definition_of_declaration() const; - - decl_base_sptr - get_earlier_declaration() const; - - void - set_earlier_declaration(decl_base_sptr declaration); - void insert_member_type(type_base_sptr t, declarations::iterator before); @@ -4013,12 +4013,6 @@ public: class_decl(const environment* env, const string& name, bool is_struct, bool is_declaration_only = true); - const class_decl_sptr - get_definition_of_declaration() const; - - const class_decl* - get_naked_definition_of_declaration() const; - virtual string get_pretty_representation(bool internal = false, bool qualified_name = true) const; diff --git a/src/abg-comp-filter.cc b/src/abg-comp-filter.cc index 702d223..9b87ee7 100644 --- a/src/abg-comp-filter.cc +++ b/src/abg-comp-filter.cc @@ -118,6 +118,25 @@ there_is_a_decl_only_class(const class_decl_sptr& class1, return false; } +/// Test if there is a enum that is declaration-only among the two +/// enums in parameter. +/// +/// @param enum1 the first enum to consider. +/// +/// @param enum2 the second enum to consider. +/// +/// @return true if either enums are declaration-only, false +/// otherwise. +static bool +there_is_a_decl_only_enum(const enum_type_decl_sptr& enum1, + const enum_type_decl_sptr& enum2) +{ + if ((enum1 && enum1->get_is_declaration_only()) + || (enum2 && enum2->get_is_declaration_only())) + return true; + return false; +} + /// Test if the diff involves a declaration-only class. /// /// @param diff the class diff to consider. @@ -146,7 +165,9 @@ type_size_changed(const type_base_sptr f, const type_base_sptr s) || f->get_size_in_bits() == 0 || s->get_size_in_bits() == 0 || there_is_a_decl_only_class(is_compatible_with_class_type(f), - is_compatible_with_class_type(s))) + is_compatible_with_class_type(s)) + || there_is_a_decl_only_enum(is_compatible_with_enum_type(f), + is_compatible_with_enum_type(s))) return false; return f->get_size_in_bits() != s->get_size_in_bits(); @@ -893,10 +914,8 @@ is_decl_only_class_with_size_change(const class_or_union_sptr& first, if (!first || !second) return false; - class_or_union_sptr f = - look_through_decl_only_class(first); - class_or_union_sptr s = - look_through_decl_only_class(second); + class_or_union_sptr f = look_through_decl_only_class(first); + class_or_union_sptr s = look_through_decl_only_class(second); return is_decl_only_class_with_size_change(*f, *s); } @@ -929,6 +948,57 @@ is_decl_only_class_with_size_change(const diff *diff) return is_decl_only_class_with_size_change(f, s); } +/// Test if two @ref decl_base_sptr are different just by the +/// fact that one is decl-only and the other one is defined. +/// +/// @param first the first decl to consider. +/// +/// @param second the second decl to consider. +/// +/// @return true iff the two arguments are different just by the fact +/// that one is decl-only and the other one is defined. +bool +has_decl_only_def_change(const decl_base_sptr& first, + const decl_base_sptr& second) +{ + if (!first || !second) + return false; + + decl_base_sptr f = + look_through_decl_only(first); + decl_base_sptr s = + look_through_decl_only(second); + + if (f->get_qualified_name() != s->get_qualified_name()) + return false; + + return (f->get_is_declaration_only() != s->get_is_declaration_only()); +} + +/// Test if a diff carries a change in which the two decls are +/// different by the fact that one is a decl-only and the other one is +/// defined. +/// +/// @param diff the diff node to consider. +/// +/// @return true if the diff carries a change in which the two decls +/// are different by the fact that one is a decl-only and the other +/// one is defined. +bool +has_decl_only_def_change(const diff *d) +{ + if (!d) + return false; + + decl_base_sptr f = + look_through_decl_only(is_decl(d->first_subject())); + decl_base_sptr s = + look_through_decl_only(is_decl(d->second_subject())); + + return has_decl_only_def_change(f, s); +} + + /// Test if two @ref class_or_union_sptr are different just by the /// fact that one is decl-only and the other one is defined. /// @@ -956,6 +1026,31 @@ has_class_decl_only_def_change(const class_or_union_sptr& first, return (f->get_is_declaration_only() != s->get_is_declaration_only()); } +/// Test if two @ref enum_sptr are different just by the +/// fact that one is decl-only and the other one is defined. +/// +/// @param first the first enum to consider. +/// +/// @param second the second enum to consider. +/// +/// @return true iff the two arguments are different just by the fact +/// that one is decl-only and the other one is defined. +bool +has_enum_decl_only_def_change(const enum_type_decl_sptr& first, + const enum_type_decl_sptr& second) +{ + if (!first || !second) + return false; + + enum_type_decl_sptr f = look_through_decl_only_enum(first); + enum_type_decl_sptr s = look_through_decl_only_enum(second); + + if (f->get_qualified_name() != s->get_qualified_name()) + return false; + + return (f->get_is_declaration_only() != s->get_is_declaration_only()); +} + /// Test if a class_or_union_diff carries a change in which the two /// classes are different by the fact that one is a decl-only and the /// other one is defined. @@ -980,6 +1075,28 @@ has_class_decl_only_def_change(const diff *diff) return has_class_decl_only_def_change(f, s); } +/// Test if a enum_diff carries a change in which the two enums are +/// different by the fact that one is a decl-only and the other one is +/// defined. +/// +/// @param diff the diff node to consider. +/// +/// @return true if the enum_diff carries a change in which the two +/// enums are different by the fact that one is a decl-only and the +/// other one is defined. +bool +has_enum_decl_only_def_change(const diff *diff) +{ + const enum_diff *d = dynamic_cast<const enum_diff*>(diff); + if (!d) + return false; + + enum_type_decl_sptr f = look_through_decl_only_enum(d->first_enum()); + enum_type_decl_sptr s = look_through_decl_only_enum(d->second_enum()); + + return has_enum_decl_only_def_change(f, s); +} + /// Test if a diff node carries a basic type name change. /// /// @param d the diff node to consider. @@ -1517,7 +1634,8 @@ categorize_harmless_diff_node(diff *d, bool pre) decl_base_sptr f = is_decl(d->first_subject()), s = is_decl(d->second_subject()); - if (has_class_decl_only_def_change(d)) + if (has_class_decl_only_def_change(d) + || has_enum_decl_only_def_change(d)) category |= TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY; if (access_changed(f, s)) @@ -1608,6 +1726,7 @@ categorize_harmful_diff_node(diff *d, bool pre) // // TODO: be more specific -- not all size changes are harmful. if (!has_class_decl_only_def_change(d) + && !has_enum_decl_only_def_change(d) && (type_size_changed(f, s) || data_member_offset_changed(f, s) || non_static_data_member_type_size_changed(f, s) diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc index d0f1d21..b6f065f 100644 --- a/src/abg-comparison.cc +++ b/src/abg-comparison.cc @@ -2827,13 +2827,15 @@ try_to_diff<class_decl>(const type_or_decl_base_sptr first, if (f->get_is_declaration_only()) { - class_decl_sptr f2 = f->get_definition_of_declaration(); + class_decl_sptr f2 = + is_class_type (f->get_definition_of_declaration()); if (f2) f = f2; } if (s->get_is_declaration_only()) { - class_decl_sptr s2 = s->get_definition_of_declaration(); + class_decl_sptr s2 = + is_class_type(s->get_definition_of_declaration()); if (s2) s = s2; } @@ -10953,8 +10955,8 @@ struct leaf_diff_node_marker_visitor : public diff_node_visitor // typedef change which underlying type is an anonymous // struct/union. && !is_anonymous_class_or_union_diff(d) - // Don't show decl-only-ness changes of classes either. - && !filtering::has_class_decl_only_def_change(d) + // Don't show decl-only-ness changes either. + && !filtering::has_decl_only_def_change(d) // Sometime, we can encounter artifacts of bogus DWARF that // yield a diff node for a decl-only class (and empty class // with the is_declaration flag set) that carries a non-zero diff --git a/src/abg-default-reporter.cc b/src/abg-default-reporter.cc index 2acb695..cbf8c2b 100644 --- a/src/abg-default-reporter.cc +++ b/src/abg-default-reporter.cc @@ -99,6 +99,25 @@ default_reporter::report(const enum_diff& d, ostream& out, enum_type_decl_sptr first = d.first_enum(), second = d.second_enum(); const diff_context_sptr& ctxt = d.context(); + + // Report enum decl-only <-> definition changes. + if (ctxt->get_allowed_category() & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY) + if (filtering::has_enum_decl_only_def_change(first, second)) + { + string was = + first->get_is_declaration_only() + ? " was a declaration-only enum type" + : " was a defined enum type"; + + string is_now = + second->get_is_declaration_only() + ? " and is now a declaration-only enum type" + : " and is now a defined enum type"; + + out << indent << "enum type " << name << was << is_now << "\n"; + return; + } + report_name_size_and_alignment_changes(first, second, ctxt, out, indent); maybe_report_diff_for_member(first, second, ctxt, out, indent); diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc index cf789d0..afe574d 100644 --- a/src/abg-dwarf-reader.cc +++ b/src/abg-dwarf-reader.cc @@ -12315,7 +12315,8 @@ get_scope_for_die(read_context& ctxt, class_decl_sptr cl = dynamic_pointer_cast<class_decl>(d); if (cl && cl->get_is_declaration_only()) { - scope_decl_sptr scop (cl->get_definition_of_declaration()); + scope_decl_sptr scop = + dynamic_pointer_cast<scope_decl>(cl->get_definition_of_declaration()); if (scop) s = scop; else diff --git a/src/abg-hash.cc b/src/abg-hash.cc index c1cdc57..5d2861f 100644 --- a/src/abg-hash.cc +++ b/src/abg-hash.cc @@ -635,7 +635,8 @@ class_or_union::hash::operator()(const class_or_union& t) const if (t.get_is_declaration_only()) { ABG_ASSERT(t.get_definition_of_declaration()); - size_t v = operator()(*t.get_definition_of_declaration()); + size_t v = operator() + (*is_class_or_union_type(t.get_definition_of_declaration())); return v; } diff --git a/src/abg-ir.cc b/src/abg-ir.cc index 4813035..940f9ec 100644 --- a/src/abg-ir.cc +++ b/src/abg-ir.cc @@ -3416,6 +3416,10 @@ struct decl_base::priv interned_string scoped_name_; interned_string linkage_name_; visibility visibility_; + decl_base_sptr declaration_; + decl_base_wptr definition_of_declaration_; + decl_base* naked_definition_of_declaration_; + bool is_declaration_only_; priv() : in_pub_sym_tab_(false), @@ -3423,7 +3427,9 @@ struct decl_base::priv is_artificial_(false), has_anonymous_parent_(false), context_(), - visibility_(VISIBILITY_DEFAULT) + visibility_(VISIBILITY_DEFAULT), + naked_definition_of_declaration_(), + is_declaration_only_() {} priv(interned_string name, const location& locus, @@ -3434,7 +3440,9 @@ struct decl_base::priv name_(name), qualified_name_(name), linkage_name_(linkage_name), - visibility_(vis) + visibility_(vis), + naked_definition_of_declaration_(), + is_declaration_only_() { is_anonymous_ = name_.empty(); has_anonymous_parent_ = false; @@ -3446,7 +3454,9 @@ struct decl_base::priv has_anonymous_parent_(false), location_(l), context_(), - visibility_(VISIBILITY_DEFAULT) + visibility_(VISIBILITY_DEFAULT), + naked_definition_of_declaration_(), + is_declaration_only_() {} ~priv() @@ -3881,6 +3891,80 @@ const interned_string& decl_base::get_scoped_name() const {return priv_->scoped_name_;} +/// If this @ref decl_base is a definition, get its earlier +/// declaration. +/// +/// @return the earlier declaration of the class, if any. +const decl_base_sptr +decl_base::get_earlier_declaration() const +{return priv_->declaration_;} + +/// set the earlier declaration of this @ref decl_base definition. +/// +/// @param d the earlier declaration to set. Note that it's set only +/// if it's a pure declaration. +void +decl_base::set_earlier_declaration(const decl_base_sptr& d) +{ + if (d && d->get_is_declaration_only()) + priv_->declaration_ = d; +} + + +/// If this @ref decl_base is declaration-only, get its definition, if +/// any. +/// +/// @return the definition of this decl-only @ref decl_base. +const decl_base_sptr +decl_base::get_definition_of_declaration() const +{return priv_->definition_of_declaration_.lock();} + +/// If this @ref decl_base is declaration-only, get its definition, +/// if any. +/// +/// Note that this function doesn't return a smart pointer, but rather +/// the underlying pointer managed by the smart pointer. So it's as +/// fast as possible. This getter is to be used in code paths that +/// are proven to be performance hot spots; especially, when comparing +/// sensitive types like enums, classes or unions. Those are compared +/// extremely frequently and thus, their access to the definition of +/// declaration must be fast. +/// +/// @return the definition of the declaration. +const decl_base* +decl_base::get_naked_definition_of_declaration() const +{return priv_->naked_definition_of_declaration_;} + +/// Test if a @ref decl_base is a declaration-only decl. +/// +/// @return true iff the current @ref decl_base is declaration-only. +bool +decl_base::get_is_declaration_only() const +{return priv_->is_declaration_only_;} + +/// Set a flag saying if the @ref enum_type_decl is a declaration-only +/// @ref enum_type_decl. +/// +/// @param f true if the @ref enum_type_decl is a decalaration-only +/// @ref enum_type_decl. +void +decl_base::set_is_declaration_only(bool f) +{ + bool update_types_lookup_map = !f && priv_->is_declaration_only_; + + priv_->is_declaration_only_ = f; + + if (update_types_lookup_map) + if (scope_decl* s = get_scope()) + { + scope_decl::declarations::iterator i; + if (s->find_iterator_for_member(this, i)) + maybe_update_types_lookup_map(*i); + else + ABG_ASSERT_NOT_REACHED; + } +} + change_kind operator|(change_kind l, change_kind r) { @@ -6686,7 +6770,7 @@ get_location(const decl_base_sptr& decl) if (class_or_union_sptr c = is_class_or_union_type(decl)) if (c->get_is_declaration_only() && c->get_definition_of_declaration()) { - c = c->get_definition_of_declaration(); + c = is_class_or_union_type(c->get_definition_of_declaration()); loc = c->get_location(); } } @@ -7925,6 +8009,38 @@ typedef_decl* is_typedef(type_base* t) {return dynamic_cast<typedef_decl*>(t);} +/// Test if a type is a enum. This function looks through typedefs. +/// +/// @parm t the type to consider. +/// +/// @return the enum_decl if @p t is a enum_decl or null otherwise. +enum_type_decl_sptr +is_compatible_with_enum_type(const type_base_sptr& t) +{ + if (!t) + return enum_type_decl_sptr(); + + // Normally we should strip typedefs entirely, but this is + // potentially costly, especially on binaries with huge changesets + // like the Linux Kernel. So we just get the leaf types for now. + // + // Maybe there should be an option by which users accepts to pay the + // CPU usage toll in exchange for finer filtering? + + // type_base_sptr ty = strip_typedef(t); + type_base_sptr ty = peel_typedef_type(t);; + return is_enum_type(ty); +} + +/// Test if a type is a enum. This function looks through typedefs. +/// +/// @parm t the type to consider. +/// +/// @return the enum_decl if @p t is a enum_decl or null otherwise. +enum_type_decl_sptr +is_compatible_with_enum_type(const decl_base_sptr& t) +{return is_compatible_with_enum_type(is_type(t));} + /// Test if a decl is an enum_type_decl /// /// @param d the decl to test for. @@ -8270,24 +8386,19 @@ is_method_type(type_or_decl_base* t) /// @param the_klass the class (or union) to consider. /// /// @return either the definition of the class, or the class itself. +class_or_union* +look_through_decl_only_class(class_or_union* the_class) +{return is_class_or_union_type(look_through_decl_only(the_class));} + +/// If a class (or union) is a decl-only class, get its definition. +/// Otherwise, just return the initial class. +/// +/// @param the_klass the class (or union) to consider. +/// +/// @return either the definition of the class, or the class itself. class_or_union_sptr look_through_decl_only_class(const class_or_union& the_class) -{ - class_or_union_sptr klass; - if (the_class.get_is_declaration_only()) - klass = the_class.get_definition_of_declaration(); - - if (!klass) - return klass; - - while (klass - && klass->get_is_declaration_only() - && klass->get_definition_of_declaration()) - klass = klass->get_definition_of_declaration(); - - ABG_ASSERT(klass); - return klass; -} +{return is_class_or_union_type(look_through_decl_only(the_class));} /// If a class (or union) is a decl-only class, get its definition. /// Otherwise, just return the initial class. @@ -8297,13 +8408,85 @@ look_through_decl_only_class(const class_or_union& the_class) /// @return either the definition of the class, or the class itself. class_or_union_sptr look_through_decl_only_class(class_or_union_sptr klass) +{return is_class_or_union_type(look_through_decl_only(klass));} + +/// If a enum is a decl-only enum, get its definition. +/// Otherwise, just return the initial enum. +/// +/// @param the_enum the enum to consider. +/// +/// @return either the definition of the enum, or the enum itself. +enum_type_decl_sptr +look_through_decl_only_enum(const enum_type_decl& the_enum) +{return is_enum_type(look_through_decl_only(the_enum));} + +/// If a enum is a decl-only enum, get its definition. +/// Otherwise, just return the initial enum. +/// +/// @param enom the enum to consider. +/// +/// @return either the definition of the enum, or the enum itself. +enum_type_decl_sptr +look_through_decl_only_enum(enum_type_decl_sptr enom) +{return is_enum_type(look_through_decl_only(enom));} + +/// If a decl is decl-only get its definition. Otherwise, just return nil. +/// +/// @param d the decl to consider. +/// +/// @return either the definition of the decl, or nil. +decl_base_sptr +look_through_decl_only(const decl_base& d) +{ + decl_base_sptr decl; + if (d.get_is_declaration_only()) + decl = d.get_definition_of_declaration(); + + if (!decl) + return decl; + + while (decl + && decl->get_is_declaration_only() + && decl->get_definition_of_declaration()) + decl = decl->get_definition_of_declaration(); + + ABG_ASSERT(decl); + return decl; +} + +/// If a decl is decl-only enum, get its definition. Otherwise, just +/// return the initial decl. +/// +/// @param d the decl to consider. +/// +/// @return either the definition of the enum, or the decl itself. +decl_base* +look_through_decl_only(decl_base* d) +{ + if (!d) + return d; + + decl_base* result = look_through_decl_only(*d).get(); + if (!result) + result = d; + + return result; +} + +/// If a decl is decl-only get its definition. Otherwise, just return nil. +/// +/// @param d the decl to consider. +/// +/// @return either the definition of the decl, or nil. +decl_base_sptr +look_through_decl_only(const decl_base_sptr& d) { - if (!klass) - return klass; + if (!d) + return d; - class_or_union_sptr result = look_through_decl_only_class(*klass); + decl_base_sptr result = look_through_decl_only(*d); if (!result) - result = klass; + result = d; return result; } @@ -10166,6 +10349,37 @@ lookup_enum_type(const interned_string& qualified_name, const corpus& corp) return result; } +/// Look into a given corpus to find the enum type*s* that have a +/// given qualified name. +/// +/// @param qualified_name the qualified name of the type to look for. +/// +/// @param corp the corpus to look into. +/// +/// @return the vector of enum types that which name is @p qualified_name. +const type_base_wptrs_type * +lookup_enum_types(const interned_string& qualified_name, const corpus& corp) +{ + const istring_type_base_wptrs_map_type& m = corp.get_types().enum_types(); + + return lookup_types_in_map(qualified_name, m); +} + +/// Look into a given corpus to find the enum type*s* that have a +/// given qualified name. +/// +/// @param qualified_name the qualified name of the type to look for. +/// +/// @param corp the corpus to look into. +/// +/// @return the vector of enum types that which name is @p qualified_name. +const type_base_wptrs_type* +lookup_enum_types(const string& qualified_name, const corpus& corp) +{ + interned_string s = corp.get_environment()->intern(qualified_name); + return lookup_enum_types(s, corp); +} + /// Look up an @ref enum_type_decl from a given corpus, by its location. /// /// @param loc the location to consider. @@ -10767,7 +10981,8 @@ maybe_update_types_lookup_map<class_decl>(const class_decl_sptr& class_type, bool update_qname_map = true; if (type->get_is_declaration_only()) { - if (class_decl_sptr def = class_type->get_definition_of_declaration()) + if (class_decl_sptr def = + is_class_type(class_type->get_definition_of_declaration())) type = def; else update_qname_map = false; @@ -11683,10 +11898,8 @@ types_defined_same_linux_kernel_corpus_public(const type_base& t1, // Look through declaration-only types. That is, get the associated // definition type. - if (c1 && c1->get_is_declaration_only()) - c1 = c1->get_definition_of_declaration().get(); - if (c2 && c2->get_is_declaration_only()) - c2 = c2->get_definition_of_declaration().get(); + c1 = look_through_decl_only_class(c1); + c2 = look_through_decl_only_class(c2); if (c1 && c2) { @@ -12084,6 +12297,22 @@ re_canonicalize(type_base_sptr t) return canonicalize(t); } +/// Set the definition of this declaration-only @ref decl_base. +/// +/// @param d the new definition to set. +void +decl_base::set_definition_of_declaration(const decl_base_sptr& d) +{ + ABG_ASSERT(get_is_declaration_only()); + priv_->definition_of_declaration_ = d; + priv_->definition_of_declaration_ = d; + if (type_base *t = is_type(this)) + if (type_base_sptr canonical_type = is_type(d)->get_canonical_type()) + t->priv_->canonical_type = canonical_type; + + priv_->naked_definition_of_declaration_ = const_cast<decl_base*>(d.get()); +} + /// The constructor of @ref type_base. /// /// @param s the size of the type, in bits. @@ -14983,7 +15212,6 @@ class enum_type_decl::priv priv(); public: - priv(type_base_sptr underlying_type, enumerators& enumerators) : underlying_type_(underlying_type), @@ -17992,9 +18220,6 @@ function_decl::parameter::get_pretty_representation(bool internal, struct class_or_union::priv { typedef_decl_wptr naming_typedef_; - decl_base_sptr declaration_; - class_or_union_wptr definition_of_declaration_; - class_or_union* naked_definition_of_declaration_; member_types member_types_; data_members data_members_; data_members non_static_data_members_; @@ -18006,21 +18231,16 @@ struct class_or_union::priv string_mem_fn_ptr_map_type signature_2_mem_fn_map_; member_function_templates member_function_templates_; member_class_templates member_class_templates_; - bool is_declaration_only_; priv() - : naked_definition_of_declaration_(), - is_declaration_only_(false) {} priv(class_or_union::member_types& mbr_types, class_or_union::data_members& data_mbrs, class_or_union::member_functions& mbr_fns) - : naked_definition_of_declaration_(), - member_types_(mbr_types), + : member_types_(mbr_types), data_members_(data_mbrs), - member_functions_(mbr_fns), - is_declaration_only_(false) + member_functions_(mbr_fns) { for (data_members::const_iterator i = data_members_.begin(); i != data_members_.end(); @@ -18029,11 +18249,6 @@ struct class_or_union::priv non_static_data_members_.push_back(*i); } - priv(bool is_declaration_only) - : naked_definition_of_declaration_(), - is_declaration_only_(is_declaration_only) - {} - /// Mark a class or union or union as being currently compared using /// the class_or_union== operator. /// @@ -18249,8 +18464,10 @@ class_or_union::class_or_union(const environment* env, const string& name, decl_base(env, name, location(), name), type_base(env, 0, 0), scope_type_decl(env, name, 0, 0, location()), - priv_(new priv(is_declaration_only)) -{} + priv_(new priv) +{ + set_is_declaration_only(is_declaration_only); +} /// This implements the ir_traversable_base::traverse pure virtual /// function. @@ -18470,7 +18687,8 @@ size_t class_or_union::get_alignment_in_bits() const { if (get_is_declaration_only() && get_definition_of_declaration()) - return get_definition_of_declaration()->get_alignment_in_bits(); + return is_class_or_union_type + (get_definition_of_declaration())->get_alignment_in_bits(); return type_base::get_alignment_in_bits(); } @@ -18485,7 +18703,8 @@ void class_or_union::set_alignment_in_bits(size_t a) { if (get_is_declaration_only() && get_definition_of_declaration()) - get_definition_of_declaration()->set_alignment_in_bits(a); + is_class_or_union_type + (get_definition_of_declaration()) ->set_alignment_in_bits(a); else type_base::set_alignment_in_bits(a); } @@ -18500,7 +18719,8 @@ void class_or_union::set_size_in_bits(size_t s) { if (get_is_declaration_only() && get_definition_of_declaration()) - get_definition_of_declaration()->set_size_in_bits(s); + is_class_or_union_type + (get_definition_of_declaration())->set_size_in_bits(s); else type_base::set_size_in_bits(s); } @@ -18515,42 +18735,12 @@ size_t class_or_union::get_size_in_bits() const { if (get_is_declaration_only() && get_definition_of_declaration()) - return get_definition_of_declaration()->get_size_in_bits(); + return is_class_or_union_type + (get_definition_of_declaration())->get_size_in_bits(); return type_base::get_size_in_bits(); } -/// Test if a @ref class_or_union is a declaration-only @ref -/// class_or_union. -/// -/// @return true iff the current @ref class_or_union is a -/// declaration-only @ref class_or_union. -bool -class_or_union::get_is_declaration_only() const -{return priv_->is_declaration_only_;} - -/// Set a flag saying if the @ref class_or_union is a declaration-only -/// @ref class_or_union. -/// -/// @param f true if the @ref class_or_union is a decalaration-only -/// @ref class_or_union. -void -class_or_union::set_is_declaration_only(bool f) -{ - bool update_types_lookup_map = !f && priv_->is_declaration_only_; - - priv_->is_declaration_only_ = f; - - if (update_types_lookup_map) - if (scope_decl* s = get_scope()) - { - declarations::iterator i; - if (s->find_iterator_for_member(this, i)) - maybe_update_types_lookup_map(*i); - else - ABG_ASSERT_NOT_REACHED; - } -} /// Getter for the naming typedef of the current class. /// @@ -18582,64 +18772,6 @@ class_or_union::set_naming_typedef(const typedef_decl_sptr& typedef_type) priv_->naming_typedef_ = typedef_type; } -/// Set the definition of this declaration-only @ref class_or_union. -/// -/// @param d the new definition to set. -void -class_or_union::set_definition_of_declaration(class_or_union_sptr d) -{ - ABG_ASSERT(get_is_declaration_only()); - priv_->definition_of_declaration_ = d; - if (d->get_canonical_type()) - type_base::priv_->canonical_type = d->get_canonical_type(); - - priv_->naked_definition_of_declaration_ = d.get(); -} - -/// If this @ref class_or_union_sptr is declaration-only, get its -/// definition, if any. -/// -/// @return the definition of this decl-only class. -const class_or_union_sptr -class_or_union::get_definition_of_declaration() const -{return priv_->definition_of_declaration_.lock();} - -/// If this @ref class_or_union is declaration-only, get its -/// definition, if any. -/// -/// Note that this function doesn't return a smart pointer, but rather -/// the underlying pointer managed by the smart pointer. So it's as -/// fast as possible. This getter is to be used in code paths that -/// are proven to be performance hot spots; especially, when comparing -/// sensitive types like class or unions. Those are compared -/// extremely frequently and thus, their access to the definition of -/// declaration must be fast. -/// -/// @return the definition of the class. -const class_or_union* -class_or_union::get_naked_definition_of_declaration() const -{return priv_->naked_definition_of_declaration_;} - -/// If this @ref class_or_union_sptr is a definitin, get its earlier -/// declaration. -/// -/// @return the earlier declaration of the class, if any. -decl_base_sptr -class_or_union::get_earlier_declaration() const -{return priv_->declaration_;} - -/// set the earlier declaration of this @ref class_or_union definition. -/// -/// @param declaration the earlier declaration to set. Note that it's -/// set only if it's a pure declaration. -void -class_or_union::set_earlier_declaration(decl_base_sptr declaration) -{ - class_or_union_sptr cl = dynamic_pointer_cast<class_or_union>(declaration); - if (cl && cl->get_is_declaration_only()) - priv_->declaration_ = declaration; -} - /// Get the member types of this @ref class_or_union. /// /// @return a vector of the member types of this ref class_or_union. @@ -19087,15 +19219,16 @@ class_or_union::operator==(const decl_base& other) const if (!canonical_type && get_is_declaration_only() && get_naked_definition_of_declaration()) - canonical_type = - get_naked_definition_of_declaration()->get_naked_canonical_type(); + canonical_type = is_class_or_union_type + (get_naked_definition_of_declaration())->get_naked_canonical_type(); // Likewise for the other class. if (!other_canonical_type && op->get_is_declaration_only() && op->get_naked_definition_of_declaration()) other_canonical_type = - op->get_naked_definition_of_declaration()->get_naked_canonical_type(); + is_class_or_union_type + (op->get_naked_definition_of_declaration())->get_naked_canonical_type(); if (canonical_type && other_canonical_type) return canonical_type == other_canonical_type; @@ -19166,11 +19299,11 @@ equals(const class_or_union& l, const class_or_union& r, change_kind* k) if (l_is_decl_only || r_is_decl_only) { const class_or_union* def1 = l_is_decl_only - ? l.get_naked_definition_of_declaration() + ? is_class_or_union_type(l.get_naked_definition_of_declaration()) : &l; const class_or_union* def2 = r_is_decl_only - ? r.get_naked_definition_of_declaration() + ? is_class_or_union_type(r.get_naked_definition_of_declaration()) : &r; if (!def1 || !def2) @@ -19682,30 +19815,6 @@ class_decl::on_canonical_type_set() sort_virtual_member_functions(i->second); } -/// If this @ref class_decl is declaration-only, get its definition, -/// if any. -/// -/// @return the definition of the class. -const class_decl_sptr -class_decl::get_definition_of_declaration() const -{return is_class_type(class_or_union::get_definition_of_declaration());} - -/// If this @ref class_decl is declaration-only, get its definition, -/// if any. -/// -/// Note that this function doesn't return a smart pointer, but rather -/// the underlying pointer managed by the smart pointer. So it's as -/// fast as possible. This getter is to be used in code paths that -/// are proven to be performance hot spots; especially, when comparing -/// sensitive types like class or unions. Those are compared -/// extremely frequently and thus, their access to the definition of -/// declaration must be fast. -/// -/// @return the definition of the class. -const class_decl* -class_decl::get_naked_definition_of_declaration() const -{return is_class_type(class_or_union::get_naked_definition_of_declaration());} - /// Set the "is-struct" flag of the class. /// /// @param f the new value of the flag. @@ -20836,14 +20945,16 @@ class_decl::operator==(const decl_base& other) const && get_is_declaration_only() && get_naked_definition_of_declaration()) canonical_type = - get_naked_definition_of_declaration()->get_naked_canonical_type(); + is_class_type + (get_naked_definition_of_declaration())->get_naked_canonical_type(); // Likewise for the other class. if (!other_canonical_type && op->get_is_declaration_only() && op->get_naked_definition_of_declaration()) other_canonical_type = - op->get_naked_definition_of_declaration()->get_naked_canonical_type(); + is_class_type + (op->get_naked_definition_of_declaration())->get_naked_canonical_type(); if (canonical_type && other_canonical_type) return canonical_type == other_canonical_type; @@ -22845,7 +22956,8 @@ hash_type(const type_base *t) // The is a declaration-only class, so it has no canonical // type; but then it's class definition has one. Let's // use that one. - return hash_type(cl->get_naked_definition_of_declaration()); + return hash_type + (is_class_type(cl->get_naked_definition_of_declaration())); else { // The class really has no canonical type, let's use the
Hello Giuliano, Giuliano Procida <gprocida@google.com> a écrit: > Hi Dodji. > > Overall this looks like an excellent compromise. In terms of the > surgery on the type hierarchy, my main concerns would be that > > 1. things that are not class/union/enum but which fall under decl_base > continue to get the same treatment Agreed. > 2. old places where class/union had declaration-only manipulation and > new places where enums have the same both get the right down-casting Yes. > It looks like these are there. I have some further comments in-line, > nothing significant. Thanks. [...] >> +bool >> +has_decl_only_def_change(const decl_base_sptr& first, >> + const decl_base_sptr& second) >> +{ >> + if (!first || !second) >> + return false; >> + >> + decl_base_sptr f = >> + look_through_decl_only(first); >> + decl_base_sptr s = >> + look_through_decl_only(second); >> + >> + if (f->get_qualified_name() != s->get_qualified_name()) >> + return false; >> + >> + return (f->get_is_declaration_only() != s->get_is_declaration_only()); > > This return statement doesn't need the outer ( ). Fixed. [...] >> /// Test if two @ref class_or_union_sptr are different just by the >> /// fact that one is decl-only and the other one is defined. >> /// >> @@ -956,6 +1026,31 @@ has_class_decl_only_def_change(const class_or_union_sptr& first, >> return (f->get_is_declaration_only() != s->get_is_declaration_only()); > > Same here on the return statement. Fixed. [...] >> +bool >> +has_enum_decl_only_def_change(const enum_type_decl_sptr& first, >> + const enum_type_decl_sptr& second) >> +{ >> + if (!first || !second) >> + return false; >> + >> + enum_type_decl_sptr f = look_through_decl_only_enum(first); >> + enum_type_decl_sptr s = look_through_decl_only_enum(second); >> + >> + if (f->get_qualified_name() != s->get_qualified_name()) >> + return false; >> + >> + return (f->get_is_declaration_only() != s->get_is_declaration_only()); > > And again. Fixed. [...] >> @@ -3423,7 +3427,9 @@ struct decl_base::priv >> is_artificial_(false), >> has_anonymous_parent_(false), >> context_(), >> - visibility_(VISIBILITY_DEFAULT) >> + visibility_(VISIBILITY_DEFAULT), >> + naked_definition_of_declaration_(), >> + is_declaration_only_() > > Would be clearer to say (false). Fixed. >> {} >> >> priv(interned_string name, const location& locus, >> @@ -3434,7 +3440,9 @@ struct decl_base::priv >> name_(name), >> qualified_name_(name), >> linkage_name_(linkage_name), >> - visibility_(vis) >> + visibility_(vis), >> + naked_definition_of_declaration_(), >> + is_declaration_only_() > > Same here. Fixed. >> { >> is_anonymous_ = name_.empty(); >> has_anonymous_parent_ = false; >> @@ -3446,7 +3454,9 @@ struct decl_base::priv >> has_anonymous_parent_(false), >> location_(l), >> context_(), >> - visibility_(VISIBILITY_DEFAULT) >> + visibility_(VISIBILITY_DEFAULT), >> + naked_definition_of_declaration_(), >> + is_declaration_only_() > > And again. Fixed. [...] >> +/// Set a flag saying if the @ref enum_type_decl is a declaration-only >> +/// @ref enum_type_decl. >> +/// >> +/// @param f true if the @ref enum_type_decl is a decalaration-only > > Typo: decalaration / declaration. Fixed. [...] >> +/// Test if a type is a enum. This function looks through typedefs. > > Typo: a enum / an enum. Fixed. [...] >> +/// Test if a type is a enum. This function looks through typedefs. > > Same typo. Fixed. >> +/// >> +/// @parm t the type to consider. >> +/// >> +/// @return the enum_decl if @p t is a enum_decl or null otherwise. > > Technically a typo: a enum_decl / an enum_decl. > I'm not sure how it will render if you @ref the types. Fixed. >> +enum_type_decl_sptr >> +is_compatible_with_enum_type(const decl_base_sptr& t) >> +{return is_compatible_with_enum_type(is_type(t));} >> + >> /// Test if a decl is an enum_type_decl >> /// >> /// @param d the decl to test for. >> @@ -8270,24 +8386,19 @@ is_method_type(type_or_decl_base* t) >> /// @param the_klass the class (or union) to consider. > > Parameter is the_class. Fixed. >> /// >> /// @return either the definition of the class, or the class itself. >> +class_or_union* >> +look_through_decl_only_class(class_or_union* the_class) >> +{return is_class_or_union_type(look_through_decl_only(the_class));} >> + >> +/// If a class (or union) is a decl-only class, get its definition. >> +/// Otherwise, just return the initial class. >> +/// >> +/// @param the_klass the class (or union) to consider. > > Same here. Fixed. [...] >> +decl_base_sptr >> +look_through_decl_only(const decl_base& d) >> +{ >> + decl_base_sptr decl; >> + if (d.get_is_declaration_only()) >> + decl = d.get_definition_of_declaration(); >> + >> + if (!decl) >> + return decl; >> + >> + while (decl >> + && decl->get_is_declaration_only() >> + && decl->get_definition_of_declaration()) >> + decl = decl->get_definition_of_declaration(); >> + >> + ABG_ASSERT(decl); >> + return decl; > > I had a suspicion that this code could be simplified a while ago. > > You should be able to simplify it to (something like): > > look_through_decl_only_class(class_or_union_sptr klass) > { > if (!klass) > return klass; > while (klass->get_is_declaration_only() > && klass->get_definition_of_declaration()) > klass = klass->get_definition_of_declaration(); > return klass; > } > > This is two things: > 1. The function is simpler if it takes a (shared) pointer argument. > You probably don't need the other overload. Actually, I prefer keeping the function that takes reference. It's reused in the overload that takes a pointer. Also, I have some test/play programs on the side that use types instantiated on the stack etc and that make use of these. So they are useful in general, I think. > 2. You don't need to retest decl on every loop or assert it at the > end, just check once at the top as the loop condition preserves the > invariant. Yes, you are correct. I have made this change in the updated patch. Thanks. [...] [...] >> +/// Look into a given corpus to find the enum type*s* that have a >> +/// given qualified name. >> +/// >> +/// @param qualified_name the qualified name of the type to look for. >> +/// >> +/// @param corp the corpus to look into. >> +/// >> +/// @return the vector of enum types that which name is @p qualified_name. > > Suggest: "that which name is" -> "named" (or "which have the name") > (and again, below) Of course. Fixed. [...] Please find below an updated patch that is present in my updated dodji/incomp-enum branch. Thanks. From 377b577cbbdc313e78b58631f5fb9bcc2c913a25 Mon Sep 17 00:00:00 2001 From: Giuliano Procida <gprocida@google.com> Date: Wed, 10 Jun 2020 12:59:35 +0100 Subject: [PATCH 1/4] Support incomplete enums in core and diff code. This is an initial implementation of the support for incomplete, also known as forward-declared, enum types. I've not made any attempt to refactor or share logic with the struct/union code. * include/abg-comp-filter.h (has_decl_only_def_change) : Declare New function. * src/abg-comp-filter.cc (there_is_a_decl_only_enum): Define new static function and ... (type_size_changed): ... use it here. (has_decl_only_def_change): Define new function and ... (categorize_harm{less, ful}_diff_node): ... use it here. * include/abg-fwd.h (enums_type, decl_base_wptr): Declare new typedefs. (look_through_decl_only_class): Declare new overload for class_or_union*. (is_compatible_with_enum_type, is_compatible_with_enum_type) (look_through_decl_only, lookup_enum_types, lookup_enum_types): Declare new functions. * include/abg-ir.h (decl_base::{get_is_declaration_only, set_is_declaration_only, set_definition_of_declaration, get_definition_of_declaration, get_naked_definition_of_declaration}): Declare new member functions. They were moved here from the class_or_union class. (class_or_union::{get_earlier_declaration, set_earlier_declaration, get_definition_of_declaration, set_definition_of_declaration, get_naked_definition_of_declaration, get_is_declaration_only, set_is_declaration_only}): Remove these member functions. * src/abg-ir.cc (decl_base::priv::{declaration_, definition_of_declaration_, naked_definition_of_declaration_, is_declaration_only_}): Define data members. Moved here from class_or_union. (decl_base::priv::priv): Adjust to initialize the new data members. (decl_base::{get_earlier_declaration, set_earlier_declaration, get_definition_of_declaration, get_naked_definition_of_declaration, get_is_declaration_only, set_is_declaration_only, set_definition_of_declaration}): Define member functions. (operator|): In the overload for (change_kind, change_kind), adjust the return type of the call to decl_base::get_definition_of_declaration. (look_through_decl_only): Define new function. (look_through_decl_only_class): Adjust. (look_through_decl_only_enum): Likewise. (maybe_update_types_lookup_map<class_decl>): Adjust return type of call to decl_base::get_definition_of_declaration. (types_defined_same_linux_kernel_corpus_public): Use look_through_decl_only_class rather than open coding it. (class_or_union::priv::{declaration_, definition_of_declaration_, naked_definition_of_declaration_, is_declaration_only_}): Remove these data members. They are now carried by decl_base::priv. (class_or_union::{g,s}et_alignment_in_bits): Adjust. (class_or_union::{g,s}et_size_in_bits): Likewise. (class_or_union::operator==): Likewise. (equals): Adjust the overload for class_or_union. (is_compatible_with_enum_type) * src/abg-comparison.cc (try_to_diff<class_decl>): Adjust the return type of decl_base::get_definition_of_declaration. (leaf_diff_node_marker_visitor::visit_begin): Use filtering::has_decl_only_def_change rather than filtering::has_class_decl_only_def_change. Decl-only changes to enums (or any other type really) will thus not be recorded as leaf changes. * src/abg-dwarf-reader.cc (get_scope_for_die): Adjust return type of decl_base::get_definition_of_declaration. * src/abg-default-reporter.cc (default_reporter::report): Report enum decl-only <-> definition changes. * src/abg-hash.cc (class_or_union::hash::operator()): In the overload for class_or_union& adjust the return type for decl_base::get_definition_of_declaration. Signed-off-by: Giuliano Procida <gprocida@google.com> Signed-off-by: Dodji Seketeli <dodji@redhat.com> --- include/abg-comp-filter.h | 14 ++ include/abg-fwd.h | 36 ++++ include/abg-ir.h | 48 ++--- src/abg-comp-filter.cc | 133 ++++++++++++- src/abg-comparison.cc | 10 +- src/abg-default-reporter.cc | 19 ++ src/abg-dwarf-reader.cc | 3 +- src/abg-hash.cc | 3 +- src/abg-ir.cc | 472 +++++++++++++++++++++++++++----------------- 9 files changed, 519 insertions(+), 219 deletions(-) diff --git a/include/abg-comp-filter.h b/include/abg-comp-filter.h index 8113003..556bad4 100644 --- a/include/abg-comp-filter.h +++ b/include/abg-comp-filter.h @@ -65,13 +65,27 @@ bool is_decl_only_class_with_size_change(const diff *diff); bool +has_decl_only_def_change(const decl_base_sptr& first, + const decl_base_sptr& second); + +bool +has_decl_only_def_change(const diff *d); + +bool has_class_decl_only_def_change(const class_or_union_sptr& first, const class_or_union_sptr& second); bool +has_enum_decl_only_def_change(const enum_type_decl_sptr& first, + const enum_type_decl_sptr& second); + +bool has_class_decl_only_def_change(const diff *diff); bool +has_enum_decl_only_def_change(const diff *diff); + +bool has_basic_type_name_change(const diff *); bool diff --git a/include/abg-fwd.h b/include/abg-fwd.h index f23f4a4..bfd9f88 100644 --- a/include/abg-fwd.h +++ b/include/abg-fwd.h @@ -155,6 +155,12 @@ class enum_type_decl; /// Convenience typedef for shared pointer to a @ref enum_type_decl. typedef shared_ptr<enum_type_decl> enum_type_decl_sptr; +/// Convenience typedef for a vector of @ref enum_type_decl_sptr +typedef vector<enum_type_decl_sptr> enums_type; + +/// Convenience typedef for a weak pointer to a @ref decl_base. +typedef weak_ptr<decl_base> decl_base_wptr; + class class_or_union; typedef shared_ptr<class_or_union> class_or_union_sptr; @@ -424,6 +430,12 @@ typedef_decl* is_typedef(type_base*); enum_type_decl_sptr +is_compatible_with_enum_type(const type_base_sptr&); + +enum_type_decl_sptr +is_compatible_with_enum_type(const decl_base_sptr&); + +enum_type_decl_sptr is_enum_type(const type_or_decl_base_sptr&); const enum_type_decl* @@ -513,6 +525,24 @@ look_through_decl_only_class(const class_or_union&); class_or_union_sptr look_through_decl_only_class(class_or_union_sptr); +class_or_union* +look_through_decl_only_class(class_or_union*); + +enum_type_decl_sptr +look_through_decl_only_enum(const enum_type_decl&); + +enum_type_decl_sptr +look_through_decl_only_enum(enum_type_decl_sptr); + +decl_base_sptr +look_through_decl_only(const decl_base&); + +decl_base* +look_through_decl_only(decl_base*); + +decl_base_sptr +look_through_decl_only(const decl_base_sptr&); + var_decl* is_var_decl(const type_or_decl_base*); @@ -1085,6 +1115,12 @@ lookup_enum_type(const string&, const corpus&); enum_type_decl_sptr lookup_enum_type(const interned_string&, const corpus&); +const type_base_wptrs_type* +lookup_enum_types(const interned_string&, const corpus&); + +const type_base_wptrs_type* +lookup_enum_types(const string&, const corpus&); + enum_type_decl_sptr lookup_enum_type_per_location(const interned_string&, const corpus&); diff --git a/include/abg-ir.h b/include/abg-ir.h index c2b66c4..5b13dc9 100644 --- a/include/abg-ir.h +++ b/include/abg-ir.h @@ -1553,6 +1553,27 @@ public: void set_visibility(visibility v); + const decl_base_sptr + get_earlier_declaration() const; + + void + set_earlier_declaration(const decl_base_sptr&); + + const decl_base_sptr + get_definition_of_declaration() const; + + void + set_definition_of_declaration(const decl_base_sptr&); + + const decl_base* + get_naked_definition_of_declaration() const; + + bool + get_is_declaration_only() const; + + void + set_is_declaration_only(bool f); + friend type_base_sptr canonicalize(type_base_sptr); @@ -3776,27 +3797,6 @@ public: void set_naming_typedef(const typedef_decl_sptr&); - bool - get_is_declaration_only() const; - - void - set_is_declaration_only(bool f); - - void - set_definition_of_declaration(class_or_union_sptr); - - const class_or_union_sptr - get_definition_of_declaration() const; - - const class_or_union* - get_naked_definition_of_declaration() const; - - decl_base_sptr - get_earlier_declaration() const; - - void - set_earlier_declaration(decl_base_sptr declaration); - void insert_member_type(type_base_sptr t, declarations::iterator before); @@ -4020,12 +4020,6 @@ public: class_decl(const environment* env, const string& name, bool is_struct, bool is_declaration_only = true); - const class_decl_sptr - get_definition_of_declaration() const; - - const class_decl* - get_naked_definition_of_declaration() const; - virtual string get_pretty_representation(bool internal = false, bool qualified_name = true) const; diff --git a/src/abg-comp-filter.cc b/src/abg-comp-filter.cc index 702d223..0b0fbe4 100644 --- a/src/abg-comp-filter.cc +++ b/src/abg-comp-filter.cc @@ -118,6 +118,25 @@ there_is_a_decl_only_class(const class_decl_sptr& class1, return false; } +/// Test if there is a enum that is declaration-only among the two +/// enums in parameter. +/// +/// @param enum1 the first enum to consider. +/// +/// @param enum2 the second enum to consider. +/// +/// @return true if either enums are declaration-only, false +/// otherwise. +static bool +there_is_a_decl_only_enum(const enum_type_decl_sptr& enum1, + const enum_type_decl_sptr& enum2) +{ + if ((enum1 && enum1->get_is_declaration_only()) + || (enum2 && enum2->get_is_declaration_only())) + return true; + return false; +} + /// Test if the diff involves a declaration-only class. /// /// @param diff the class diff to consider. @@ -146,7 +165,9 @@ type_size_changed(const type_base_sptr f, const type_base_sptr s) || f->get_size_in_bits() == 0 || s->get_size_in_bits() == 0 || there_is_a_decl_only_class(is_compatible_with_class_type(f), - is_compatible_with_class_type(s))) + is_compatible_with_class_type(s)) + || there_is_a_decl_only_enum(is_compatible_with_enum_type(f), + is_compatible_with_enum_type(s))) return false; return f->get_size_in_bits() != s->get_size_in_bits(); @@ -893,10 +914,8 @@ is_decl_only_class_with_size_change(const class_or_union_sptr& first, if (!first || !second) return false; - class_or_union_sptr f = - look_through_decl_only_class(first); - class_or_union_sptr s = - look_through_decl_only_class(second); + class_or_union_sptr f = look_through_decl_only_class(first); + class_or_union_sptr s = look_through_decl_only_class(second); return is_decl_only_class_with_size_change(*f, *s); } @@ -929,6 +948,57 @@ is_decl_only_class_with_size_change(const diff *diff) return is_decl_only_class_with_size_change(f, s); } +/// Test if two @ref decl_base_sptr are different just by the +/// fact that one is decl-only and the other one is defined. +/// +/// @param first the first decl to consider. +/// +/// @param second the second decl to consider. +/// +/// @return true iff the two arguments are different just by the fact +/// that one is decl-only and the other one is defined. +bool +has_decl_only_def_change(const decl_base_sptr& first, + const decl_base_sptr& second) +{ + if (!first || !second) + return false; + + decl_base_sptr f = + look_through_decl_only(first); + decl_base_sptr s = + look_through_decl_only(second); + + if (f->get_qualified_name() != s->get_qualified_name()) + return false; + + return f->get_is_declaration_only() != s->get_is_declaration_only(); +} + +/// Test if a diff carries a change in which the two decls are +/// different by the fact that one is a decl-only and the other one is +/// defined. +/// +/// @param diff the diff node to consider. +/// +/// @return true if the diff carries a change in which the two decls +/// are different by the fact that one is a decl-only and the other +/// one is defined. +bool +has_decl_only_def_change(const diff *d) +{ + if (!d) + return false; + + decl_base_sptr f = + look_through_decl_only(is_decl(d->first_subject())); + decl_base_sptr s = + look_through_decl_only(is_decl(d->second_subject())); + + return has_decl_only_def_change(f, s); +} + + /// Test if two @ref class_or_union_sptr are different just by the /// fact that one is decl-only and the other one is defined. /// @@ -953,7 +1023,32 @@ has_class_decl_only_def_change(const class_or_union_sptr& first, if (f->get_qualified_name() != s->get_qualified_name()) return false; - return (f->get_is_declaration_only() != s->get_is_declaration_only()); + return f->get_is_declaration_only() != s->get_is_declaration_only(); +} + +/// Test if two @ref enum_sptr are different just by the +/// fact that one is decl-only and the other one is defined. +/// +/// @param first the first enum to consider. +/// +/// @param second the second enum to consider. +/// +/// @return true iff the two arguments are different just by the fact +/// that one is decl-only and the other one is defined. +bool +has_enum_decl_only_def_change(const enum_type_decl_sptr& first, + const enum_type_decl_sptr& second) +{ + if (!first || !second) + return false; + + enum_type_decl_sptr f = look_through_decl_only_enum(first); + enum_type_decl_sptr s = look_through_decl_only_enum(second); + + if (f->get_qualified_name() != s->get_qualified_name()) + return false; + + return f->get_is_declaration_only() != s->get_is_declaration_only(); } /// Test if a class_or_union_diff carries a change in which the two @@ -980,6 +1075,28 @@ has_class_decl_only_def_change(const diff *diff) return has_class_decl_only_def_change(f, s); } +/// Test if a enum_diff carries a change in which the two enums are +/// different by the fact that one is a decl-only and the other one is +/// defined. +/// +/// @param diff the diff node to consider. +/// +/// @return true if the enum_diff carries a change in which the two +/// enums are different by the fact that one is a decl-only and the +/// other one is defined. +bool +has_enum_decl_only_def_change(const diff *diff) +{ + const enum_diff *d = dynamic_cast<const enum_diff*>(diff); + if (!d) + return false; + + enum_type_decl_sptr f = look_through_decl_only_enum(d->first_enum()); + enum_type_decl_sptr s = look_through_decl_only_enum(d->second_enum()); + + return has_enum_decl_only_def_change(f, s); +} + /// Test if a diff node carries a basic type name change. /// /// @param d the diff node to consider. @@ -1517,7 +1634,8 @@ categorize_harmless_diff_node(diff *d, bool pre) decl_base_sptr f = is_decl(d->first_subject()), s = is_decl(d->second_subject()); - if (has_class_decl_only_def_change(d)) + if (has_class_decl_only_def_change(d) + || has_enum_decl_only_def_change(d)) category |= TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY; if (access_changed(f, s)) @@ -1608,6 +1726,7 @@ categorize_harmful_diff_node(diff *d, bool pre) // // TODO: be more specific -- not all size changes are harmful. if (!has_class_decl_only_def_change(d) + && !has_enum_decl_only_def_change(d) && (type_size_changed(f, s) || data_member_offset_changed(f, s) || non_static_data_member_type_size_changed(f, s) diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc index d0f1d21..b6f065f 100644 --- a/src/abg-comparison.cc +++ b/src/abg-comparison.cc @@ -2827,13 +2827,15 @@ try_to_diff<class_decl>(const type_or_decl_base_sptr first, if (f->get_is_declaration_only()) { - class_decl_sptr f2 = f->get_definition_of_declaration(); + class_decl_sptr f2 = + is_class_type (f->get_definition_of_declaration()); if (f2) f = f2; } if (s->get_is_declaration_only()) { - class_decl_sptr s2 = s->get_definition_of_declaration(); + class_decl_sptr s2 = + is_class_type(s->get_definition_of_declaration()); if (s2) s = s2; } @@ -10953,8 +10955,8 @@ struct leaf_diff_node_marker_visitor : public diff_node_visitor // typedef change which underlying type is an anonymous // struct/union. && !is_anonymous_class_or_union_diff(d) - // Don't show decl-only-ness changes of classes either. - && !filtering::has_class_decl_only_def_change(d) + // Don't show decl-only-ness changes either. + && !filtering::has_decl_only_def_change(d) // Sometime, we can encounter artifacts of bogus DWARF that // yield a diff node for a decl-only class (and empty class // with the is_declaration flag set) that carries a non-zero diff --git a/src/abg-default-reporter.cc b/src/abg-default-reporter.cc index 2acb695..cbf8c2b 100644 --- a/src/abg-default-reporter.cc +++ b/src/abg-default-reporter.cc @@ -99,6 +99,25 @@ default_reporter::report(const enum_diff& d, ostream& out, enum_type_decl_sptr first = d.first_enum(), second = d.second_enum(); const diff_context_sptr& ctxt = d.context(); + + // Report enum decl-only <-> definition changes. + if (ctxt->get_allowed_category() & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY) + if (filtering::has_enum_decl_only_def_change(first, second)) + { + string was = + first->get_is_declaration_only() + ? " was a declaration-only enum type" + : " was a defined enum type"; + + string is_now = + second->get_is_declaration_only() + ? " and is now a declaration-only enum type" + : " and is now a defined enum type"; + + out << indent << "enum type " << name << was << is_now << "\n"; + return; + } + report_name_size_and_alignment_changes(first, second, ctxt, out, indent); maybe_report_diff_for_member(first, second, ctxt, out, indent); diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc index ba4e750..db43aa7 100644 --- a/src/abg-dwarf-reader.cc +++ b/src/abg-dwarf-reader.cc @@ -12315,7 +12315,8 @@ get_scope_for_die(read_context& ctxt, class_decl_sptr cl = dynamic_pointer_cast<class_decl>(d); if (cl && cl->get_is_declaration_only()) { - scope_decl_sptr scop (cl->get_definition_of_declaration()); + scope_decl_sptr scop = + dynamic_pointer_cast<scope_decl>(cl->get_definition_of_declaration()); if (scop) s = scop; else diff --git a/src/abg-hash.cc b/src/abg-hash.cc index c1cdc57..5d2861f 100644 --- a/src/abg-hash.cc +++ b/src/abg-hash.cc @@ -635,7 +635,8 @@ class_or_union::hash::operator()(const class_or_union& t) const if (t.get_is_declaration_only()) { ABG_ASSERT(t.get_definition_of_declaration()); - size_t v = operator()(*t.get_definition_of_declaration()); + size_t v = operator() + (*is_class_or_union_type(t.get_definition_of_declaration())); return v; } diff --git a/src/abg-ir.cc b/src/abg-ir.cc index a434ec6..15bf124 100644 --- a/src/abg-ir.cc +++ b/src/abg-ir.cc @@ -3416,6 +3416,10 @@ struct decl_base::priv interned_string scoped_name_; interned_string linkage_name_; visibility visibility_; + decl_base_sptr declaration_; + decl_base_wptr definition_of_declaration_; + decl_base* naked_definition_of_declaration_; + bool is_declaration_only_; priv() : in_pub_sym_tab_(false), @@ -3423,7 +3427,9 @@ struct decl_base::priv is_artificial_(false), has_anonymous_parent_(false), context_(), - visibility_(VISIBILITY_DEFAULT) + visibility_(VISIBILITY_DEFAULT), + naked_definition_of_declaration_(), + is_declaration_only_(false) {} priv(interned_string name, const location& locus, @@ -3434,7 +3440,9 @@ struct decl_base::priv name_(name), qualified_name_(name), linkage_name_(linkage_name), - visibility_(vis) + visibility_(vis), + naked_definition_of_declaration_(), + is_declaration_only_(false) { is_anonymous_ = name_.empty(); has_anonymous_parent_ = false; @@ -3446,7 +3454,9 @@ struct decl_base::priv has_anonymous_parent_(false), location_(l), context_(), - visibility_(VISIBILITY_DEFAULT) + visibility_(VISIBILITY_DEFAULT), + naked_definition_of_declaration_(), + is_declaration_only_(false) {} ~priv() @@ -3881,6 +3891,80 @@ const interned_string& decl_base::get_scoped_name() const {return priv_->scoped_name_;} +/// If this @ref decl_base is a definition, get its earlier +/// declaration. +/// +/// @return the earlier declaration of the class, if any. +const decl_base_sptr +decl_base::get_earlier_declaration() const +{return priv_->declaration_;} + +/// set the earlier declaration of this @ref decl_base definition. +/// +/// @param d the earlier declaration to set. Note that it's set only +/// if it's a pure declaration. +void +decl_base::set_earlier_declaration(const decl_base_sptr& d) +{ + if (d && d->get_is_declaration_only()) + priv_->declaration_ = d; +} + + +/// If this @ref decl_base is declaration-only, get its definition, if +/// any. +/// +/// @return the definition of this decl-only @ref decl_base. +const decl_base_sptr +decl_base::get_definition_of_declaration() const +{return priv_->definition_of_declaration_.lock();} + +/// If this @ref decl_base is declaration-only, get its definition, +/// if any. +/// +/// Note that this function doesn't return a smart pointer, but rather +/// the underlying pointer managed by the smart pointer. So it's as +/// fast as possible. This getter is to be used in code paths that +/// are proven to be performance hot spots; especially, when comparing +/// sensitive types like enums, classes or unions. Those are compared +/// extremely frequently and thus, their access to the definition of +/// declaration must be fast. +/// +/// @return the definition of the declaration. +const decl_base* +decl_base::get_naked_definition_of_declaration() const +{return priv_->naked_definition_of_declaration_;} + +/// Test if a @ref decl_base is a declaration-only decl. +/// +/// @return true iff the current @ref decl_base is declaration-only. +bool +decl_base::get_is_declaration_only() const +{return priv_->is_declaration_only_;} + +/// Set a flag saying if the @ref enum_type_decl is a declaration-only +/// @ref enum_type_decl. +/// +/// @param f true if the @ref enum_type_decl is a declaration-only +/// @ref enum_type_decl. +void +decl_base::set_is_declaration_only(bool f) +{ + bool update_types_lookup_map = !f && priv_->is_declaration_only_; + + priv_->is_declaration_only_ = f; + + if (update_types_lookup_map) + if (scope_decl* s = get_scope()) + { + scope_decl::declarations::iterator i; + if (s->find_iterator_for_member(this, i)) + maybe_update_types_lookup_map(*i); + else + ABG_ASSERT_NOT_REACHED; + } +} + change_kind operator|(change_kind l, change_kind r) { @@ -4236,7 +4320,7 @@ operator!=(const type_base_sptr& l, const type_base_sptr& r) /// Tests if a declaration has got a scope. /// -/// @param d the decalaration to consider. +/// @param d the declaration to consider. /// /// @return true if the declaration has got a scope, false otherwise. bool @@ -4245,7 +4329,7 @@ has_scope(const decl_base& d) /// Tests if a declaration has got a scope. /// -/// @param d the decalaration to consider. +/// @param d the declaration to consider. /// /// @return true if the declaration has got a scope, false otherwise. bool @@ -6686,7 +6770,7 @@ get_location(const decl_base_sptr& decl) if (class_or_union_sptr c = is_class_or_union_type(decl)) if (c->get_is_declaration_only() && c->get_definition_of_declaration()) { - c = c->get_definition_of_declaration(); + c = is_class_or_union_type(c->get_definition_of_declaration()); loc = c->get_location(); } } @@ -7925,6 +8009,40 @@ typedef_decl* is_typedef(type_base* t) {return dynamic_cast<typedef_decl*>(t);} +/// Test if a type is an enum. This function looks through typedefs. +/// +/// @parm t the type to consider. +/// +/// @return the enum_decl if @p t is an @ref enum_decl or null +/// otherwise. +enum_type_decl_sptr +is_compatible_with_enum_type(const type_base_sptr& t) +{ + if (!t) + return enum_type_decl_sptr(); + + // Normally we should strip typedefs entirely, but this is + // potentially costly, especially on binaries with huge changesets + // like the Linux Kernel. So we just get the leaf types for now. + // + // Maybe there should be an option by which users accepts to pay the + // CPU usage toll in exchange for finer filtering? + + // type_base_sptr ty = strip_typedef(t); + type_base_sptr ty = peel_typedef_type(t);; + return is_enum_type(ty); +} + +/// Test if a type is an enum. This function looks through typedefs. +/// +/// @parm t the type to consider. +/// +/// @return the enum_decl if @p t is an @ref enum_decl or null +/// otherwise. +enum_type_decl_sptr +is_compatible_with_enum_type(const decl_base_sptr& t) +{return is_compatible_with_enum_type(is_type(t));} + /// Test if a decl is an enum_type_decl /// /// @param d the decl to test for. @@ -8267,27 +8385,22 @@ is_method_type(type_or_decl_base* t) /// If a class (or union) is a decl-only class, get its definition. /// Otherwise, just return the initial class. /// -/// @param the_klass the class (or union) to consider. +/// @param the_class the class (or union) to consider. +/// +/// @return either the definition of the class, or the class itself. +class_or_union* +look_through_decl_only_class(class_or_union* the_class) +{return is_class_or_union_type(look_through_decl_only(the_class));} + +/// If a class (or union) is a decl-only class, get its definition. +/// Otherwise, just return the initial class. +/// +/// @param the_class the class (or union) to consider. /// /// @return either the definition of the class, or the class itself. class_or_union_sptr look_through_decl_only_class(const class_or_union& the_class) -{ - class_or_union_sptr klass; - if (the_class.get_is_declaration_only()) - klass = the_class.get_definition_of_declaration(); - - if (!klass) - return klass; - - while (klass - && klass->get_is_declaration_only() - && klass->get_definition_of_declaration()) - klass = klass->get_definition_of_declaration(); - - ABG_ASSERT(klass); - return klass; -} +{return is_class_or_union_type(look_through_decl_only(the_class));} /// If a class (or union) is a decl-only class, get its definition. /// Otherwise, just return the initial class. @@ -8297,13 +8410,84 @@ look_through_decl_only_class(const class_or_union& the_class) /// @return either the definition of the class, or the class itself. class_or_union_sptr look_through_decl_only_class(class_or_union_sptr klass) +{return is_class_or_union_type(look_through_decl_only(klass));} + +/// If an enum is a decl-only enum, get its definition. +/// Otherwise, just return the initial enum. +/// +/// @param the_enum the enum to consider. +/// +/// @return either the definition of the enum, or the enum itself. +enum_type_decl_sptr +look_through_decl_only_enum(const enum_type_decl& the_enum) +{return is_enum_type(look_through_decl_only(the_enum));} + +/// If an enum is a decl-only enum, get its definition. +/// Otherwise, just return the initial enum. +/// +/// @param enom the enum to consider. +/// +/// @return either the definition of the enum, or the enum itself. +enum_type_decl_sptr +look_through_decl_only_enum(enum_type_decl_sptr enom) +{return is_enum_type(look_through_decl_only(enom));} + +/// If a decl is decl-only get its definition. Otherwise, just return nil. +/// +/// @param d the decl to consider. +/// +/// @return either the definition of the decl, or nil. +decl_base_sptr +look_through_decl_only(const decl_base& d) +{ + decl_base_sptr decl; + if (d.get_is_declaration_only()) + decl = d.get_definition_of_declaration(); + + if (!decl) + return decl; + + while (decl->get_is_declaration_only() + && decl->get_definition_of_declaration()) + decl = decl->get_definition_of_declaration(); + + ABG_ASSERT(decl); + return decl; +} + +/// If a decl is decl-only enum, get its definition. Otherwise, just +/// return the initial decl. +/// +/// @param d the decl to consider. +/// +/// @return either the definition of the enum, or the decl itself. +decl_base* +look_through_decl_only(decl_base* d) +{ + if (!d) + return d; + + decl_base* result = look_through_decl_only(*d).get(); + if (!result) + result = d; + + return result; +} + +/// If a decl is decl-only get its definition. Otherwise, just return nil. +/// +/// @param d the decl to consider. +/// +/// @return either the definition of the decl, or nil. +decl_base_sptr +look_through_decl_only(const decl_base_sptr& d) { - if (!klass) - return klass; + if (!d) + return d; - class_or_union_sptr result = look_through_decl_only_class(*klass); + decl_base_sptr result = look_through_decl_only(*d); if (!result) - result = klass; + result = d; return result; } @@ -8784,7 +8968,7 @@ lookup_union_type_per_location(const string& loc, const corpus& corp) return lookup_union_type_per_location(env->intern(loc), corp); } -/// Lookup a enum type from a translation unit. +/// Lookup an enum type from a translation unit. /// /// This is done by looking the type up in the type map that is /// maintained in the translation unit. So this is as fast as @@ -8802,7 +8986,7 @@ lookup_enum_type(const interned_string& type_name, const translation_unit& tu) tu.get_types().enum_types()); } -/// Lookup a enum type from a translation unit. +/// Lookup an enum type from a translation unit. /// /// This is done by looking the type up in the type map that is /// maintained in the translation unit. So this is as fast as @@ -10004,7 +10188,7 @@ lookup_class_type(const interned_string& qualified_name, const corpus& corp) /// /// @param corp the corpus to look into. /// -/// @return the vector of class types that which name is @p qualified_name. +/// @return the vector of class types named @p qualified_name. const type_base_wptrs_type * lookup_class_types(const interned_string& qualified_name, const corpus& corp) { @@ -10103,7 +10287,7 @@ lookup_union_type(const string& type_name, const corpus& corp) return lookup_union_type(s, corp); } -/// Look into a given corpus to find a enum type which has the same +/// Look into a given corpus to find an enum type which has the same /// qualified name as a given enum type. /// /// If the per-corpus type map is non-empty (because the corpus allows @@ -10166,6 +10350,37 @@ lookup_enum_type(const interned_string& qualified_name, const corpus& corp) return result; } +/// Look into a given corpus to find the enum type*s* that have a +/// given qualified name. +/// +/// @param qualified_name the qualified name of the type to look for. +/// +/// @param corp the corpus to look into. +/// +/// @return the vector of enum types that which name is @p qualified_name. +const type_base_wptrs_type * +lookup_enum_types(const interned_string& qualified_name, const corpus& corp) +{ + const istring_type_base_wptrs_map_type& m = corp.get_types().enum_types(); + + return lookup_types_in_map(qualified_name, m); +} + +/// Look into a given corpus to find the enum type*s* that have a +/// given qualified name. +/// +/// @param qualified_name the qualified name of the type to look for. +/// +/// @param corp the corpus to look into. +/// +/// @return the vector of enum types that which name is @p qualified_name. +const type_base_wptrs_type* +lookup_enum_types(const string& qualified_name, const corpus& corp) +{ + interned_string s = corp.get_environment()->intern(qualified_name); + return lookup_enum_types(s, corp); +} + /// Look up an @ref enum_type_decl from a given corpus, by its location. /// /// @param loc the location to consider. @@ -10767,7 +10982,8 @@ maybe_update_types_lookup_map<class_decl>(const class_decl_sptr& class_type, bool update_qname_map = true; if (type->get_is_declaration_only()) { - if (class_decl_sptr def = class_type->get_definition_of_declaration()) + if (class_decl_sptr def = + is_class_type(class_type->get_definition_of_declaration())) type = def; else update_qname_map = false; @@ -11683,10 +11899,8 @@ types_defined_same_linux_kernel_corpus_public(const type_base& t1, // Look through declaration-only types. That is, get the associated // definition type. - if (c1 && c1->get_is_declaration_only()) - c1 = c1->get_definition_of_declaration().get(); - if (c2 && c2->get_is_declaration_only()) - c2 = c2->get_definition_of_declaration().get(); + c1 = look_through_decl_only_class(c1); + c2 = look_through_decl_only_class(c2); if (c1 && c2) { @@ -12079,6 +12293,23 @@ canonicalize(type_base_sptr t) return canonical; } + +/// Set the definition of this declaration-only @ref decl_base. +/// +/// @param d the new definition to set. +void +decl_base::set_definition_of_declaration(const decl_base_sptr& d) +{ + ABG_ASSERT(get_is_declaration_only()); + priv_->definition_of_declaration_ = d; + priv_->definition_of_declaration_ = d; + if (type_base *t = is_type(this)) + if (type_base_sptr canonical_type = is_type(d)->get_canonical_type()) + t->priv_->canonical_type = canonical_type; + + priv_->naked_definition_of_declaration_ = const_cast<decl_base*>(d.get()); +} + /// The constructor of @ref type_base. /// /// @param s the size of the type, in bits. @@ -14978,7 +15209,6 @@ class enum_type_decl::priv priv(); public: - priv(type_base_sptr underlying_type, enumerators& enumerators) : underlying_type_(underlying_type), @@ -17987,9 +18217,6 @@ function_decl::parameter::get_pretty_representation(bool internal, struct class_or_union::priv { typedef_decl_wptr naming_typedef_; - decl_base_sptr declaration_; - class_or_union_wptr definition_of_declaration_; - class_or_union* naked_definition_of_declaration_; member_types member_types_; data_members data_members_; data_members non_static_data_members_; @@ -18001,21 +18228,16 @@ struct class_or_union::priv string_mem_fn_ptr_map_type signature_2_mem_fn_map_; member_function_templates member_function_templates_; member_class_templates member_class_templates_; - bool is_declaration_only_; priv() - : naked_definition_of_declaration_(), - is_declaration_only_(false) {} priv(class_or_union::member_types& mbr_types, class_or_union::data_members& data_mbrs, class_or_union::member_functions& mbr_fns) - : naked_definition_of_declaration_(), - member_types_(mbr_types), + : member_types_(mbr_types), data_members_(data_mbrs), - member_functions_(mbr_fns), - is_declaration_only_(false) + member_functions_(mbr_fns) { for (data_members::const_iterator i = data_members_.begin(); i != data_members_.end(); @@ -18024,11 +18246,6 @@ struct class_or_union::priv non_static_data_members_.push_back(*i); } - priv(bool is_declaration_only) - : naked_definition_of_declaration_(), - is_declaration_only_(is_declaration_only) - {} - /// Mark a class or union or union as being currently compared using /// the class_or_union== operator. /// @@ -18244,8 +18461,10 @@ class_or_union::class_or_union(const environment* env, const string& name, decl_base(env, name, location(), name), type_base(env, 0, 0), scope_type_decl(env, name, 0, 0, location()), - priv_(new priv(is_declaration_only)) -{} + priv_(new priv) +{ + set_is_declaration_only(is_declaration_only); +} /// This implements the ir_traversable_base::traverse pure virtual /// function. @@ -18465,7 +18684,8 @@ size_t class_or_union::get_alignment_in_bits() const { if (get_is_declaration_only() && get_definition_of_declaration()) - return get_definition_of_declaration()->get_alignment_in_bits(); + return is_class_or_union_type + (get_definition_of_declaration())->get_alignment_in_bits(); return type_base::get_alignment_in_bits(); } @@ -18480,7 +18700,8 @@ void class_or_union::set_alignment_in_bits(size_t a) { if (get_is_declaration_only() && get_definition_of_declaration()) - get_definition_of_declaration()->set_alignment_in_bits(a); + is_class_or_union_type + (get_definition_of_declaration()) ->set_alignment_in_bits(a); else type_base::set_alignment_in_bits(a); } @@ -18495,7 +18716,8 @@ void class_or_union::set_size_in_bits(size_t s) { if (get_is_declaration_only() && get_definition_of_declaration()) - get_definition_of_declaration()->set_size_in_bits(s); + is_class_or_union_type + (get_definition_of_declaration())->set_size_in_bits(s); else type_base::set_size_in_bits(s); } @@ -18510,42 +18732,12 @@ size_t class_or_union::get_size_in_bits() const { if (get_is_declaration_only() && get_definition_of_declaration()) - return get_definition_of_declaration()->get_size_in_bits(); + return is_class_or_union_type + (get_definition_of_declaration())->get_size_in_bits(); return type_base::get_size_in_bits(); } -/// Test if a @ref class_or_union is a declaration-only @ref -/// class_or_union. -/// -/// @return true iff the current @ref class_or_union is a -/// declaration-only @ref class_or_union. -bool -class_or_union::get_is_declaration_only() const -{return priv_->is_declaration_only_;} - -/// Set a flag saying if the @ref class_or_union is a declaration-only -/// @ref class_or_union. -/// -/// @param f true if the @ref class_or_union is a decalaration-only -/// @ref class_or_union. -void -class_or_union::set_is_declaration_only(bool f) -{ - bool update_types_lookup_map = !f && priv_->is_declaration_only_; - - priv_->is_declaration_only_ = f; - - if (update_types_lookup_map) - if (scope_decl* s = get_scope()) - { - declarations::iterator i; - if (s->find_iterator_for_member(this, i)) - maybe_update_types_lookup_map(*i); - else - ABG_ASSERT_NOT_REACHED; - } -} /// Getter for the naming typedef of the current class. /// @@ -18577,64 +18769,6 @@ class_or_union::set_naming_typedef(const typedef_decl_sptr& typedef_type) priv_->naming_typedef_ = typedef_type; } -/// Set the definition of this declaration-only @ref class_or_union. -/// -/// @param d the new definition to set. -void -class_or_union::set_definition_of_declaration(class_or_union_sptr d) -{ - ABG_ASSERT(get_is_declaration_only()); - priv_->definition_of_declaration_ = d; - if (d->get_canonical_type()) - type_base::priv_->canonical_type = d->get_canonical_type(); - - priv_->naked_definition_of_declaration_ = d.get(); -} - -/// If this @ref class_or_union_sptr is declaration-only, get its -/// definition, if any. -/// -/// @return the definition of this decl-only class. -const class_or_union_sptr -class_or_union::get_definition_of_declaration() const -{return priv_->definition_of_declaration_.lock();} - -/// If this @ref class_or_union is declaration-only, get its -/// definition, if any. -/// -/// Note that this function doesn't return a smart pointer, but rather -/// the underlying pointer managed by the smart pointer. So it's as -/// fast as possible. This getter is to be used in code paths that -/// are proven to be performance hot spots; especially, when comparing -/// sensitive types like class or unions. Those are compared -/// extremely frequently and thus, their access to the definition of -/// declaration must be fast. -/// -/// @return the definition of the class. -const class_or_union* -class_or_union::get_naked_definition_of_declaration() const -{return priv_->naked_definition_of_declaration_;} - -/// If this @ref class_or_union_sptr is a definitin, get its earlier -/// declaration. -/// -/// @return the earlier declaration of the class, if any. -decl_base_sptr -class_or_union::get_earlier_declaration() const -{return priv_->declaration_;} - -/// set the earlier declaration of this @ref class_or_union definition. -/// -/// @param declaration the earlier declaration to set. Note that it's -/// set only if it's a pure declaration. -void -class_or_union::set_earlier_declaration(decl_base_sptr declaration) -{ - class_or_union_sptr cl = dynamic_pointer_cast<class_or_union>(declaration); - if (cl && cl->get_is_declaration_only()) - priv_->declaration_ = declaration; -} - /// Get the member types of this @ref class_or_union. /// /// @return a vector of the member types of this ref class_or_union. @@ -19082,15 +19216,16 @@ class_or_union::operator==(const decl_base& other) const if (!canonical_type && get_is_declaration_only() && get_naked_definition_of_declaration()) - canonical_type = - get_naked_definition_of_declaration()->get_naked_canonical_type(); + canonical_type = is_class_or_union_type + (get_naked_definition_of_declaration())->get_naked_canonical_type(); // Likewise for the other class. if (!other_canonical_type && op->get_is_declaration_only() && op->get_naked_definition_of_declaration()) other_canonical_type = - op->get_naked_definition_of_declaration()->get_naked_canonical_type(); + is_class_or_union_type + (op->get_naked_definition_of_declaration())->get_naked_canonical_type(); if (canonical_type && other_canonical_type) return canonical_type == other_canonical_type; @@ -19161,11 +19296,11 @@ equals(const class_or_union& l, const class_or_union& r, change_kind* k) if (l_is_decl_only || r_is_decl_only) { const class_or_union* def1 = l_is_decl_only - ? l.get_naked_definition_of_declaration() + ? is_class_or_union_type(l.get_naked_definition_of_declaration()) : &l; const class_or_union* def2 = r_is_decl_only - ? r.get_naked_definition_of_declaration() + ? is_class_or_union_type(r.get_naked_definition_of_declaration()) : &r; if (!def1 || !def2) @@ -19784,30 +19919,6 @@ class_decl::on_canonical_type_set() sort_virtual_member_functions(i->second); } -/// If this @ref class_decl is declaration-only, get its definition, -/// if any. -/// -/// @return the definition of the class. -const class_decl_sptr -class_decl::get_definition_of_declaration() const -{return is_class_type(class_or_union::get_definition_of_declaration());} - -/// If this @ref class_decl is declaration-only, get its definition, -/// if any. -/// -/// Note that this function doesn't return a smart pointer, but rather -/// the underlying pointer managed by the smart pointer. So it's as -/// fast as possible. This getter is to be used in code paths that -/// are proven to be performance hot spots; especially, when comparing -/// sensitive types like class or unions. Those are compared -/// extremely frequently and thus, their access to the definition of -/// declaration must be fast. -/// -/// @return the definition of the class. -const class_decl* -class_decl::get_naked_definition_of_declaration() const -{return is_class_type(class_or_union::get_naked_definition_of_declaration());} - /// Set the "is-struct" flag of the class. /// /// @param f the new value of the flag. @@ -20938,14 +21049,16 @@ class_decl::operator==(const decl_base& other) const && get_is_declaration_only() && get_naked_definition_of_declaration()) canonical_type = - get_naked_definition_of_declaration()->get_naked_canonical_type(); + is_class_type + (get_naked_definition_of_declaration())->get_naked_canonical_type(); // Likewise for the other class. if (!other_canonical_type && op->get_is_declaration_only() && op->get_naked_definition_of_declaration()) other_canonical_type = - op->get_naked_definition_of_declaration()->get_naked_canonical_type(); + is_class_type + (op->get_naked_definition_of_declaration())->get_naked_canonical_type(); if (canonical_type && other_canonical_type) return canonical_type == other_canonical_type; @@ -23035,7 +23148,8 @@ hash_type(const type_base *t) // The is a declaration-only class, so it has no canonical // type; but then it's class definition has one. Let's // use that one. - return hash_type(cl->get_naked_definition_of_declaration()); + return hash_type + (is_class_type(cl->get_naked_definition_of_declaration())); else { // The class really has no canonical type, let's use the
On Wed, 8 Jul 2020 at 10:22, Dodji Seketeli <dodji@seketeli.org> wrote: > > Hello Giuliano, > > Giuliano Procida <gprocida@google.com> a écrit: > > > Hi Dodji. > > > > Overall this looks like an excellent compromise. In terms of the > > surgery on the type hierarchy, my main concerns would be that > > > > 1. things that are not class/union/enum but which fall under decl_base > > continue to get the same treatment > > Agreed. > > > 2. old places where class/union had declaration-only manipulation and > > new places where enums have the same both get the right down-casting > > Yes. > > > It looks like these are there. I have some further comments in-line, > > nothing significant. > > Thanks. > > [...] > > >> +bool > >> +has_decl_only_def_change(const decl_base_sptr& first, > >> + const decl_base_sptr& second) > >> +{ > >> + if (!first || !second) > >> + return false; > >> + > >> + decl_base_sptr f = > >> + look_through_decl_only(first); > >> + decl_base_sptr s = > >> + look_through_decl_only(second); > >> + > >> + if (f->get_qualified_name() != s->get_qualified_name()) > >> + return false; > >> + > >> + return (f->get_is_declaration_only() != s->get_is_declaration_only()); > > > > This return statement doesn't need the outer ( ). > > Fixed. > > [...] > > >> /// Test if two @ref class_or_union_sptr are different just by the > >> /// fact that one is decl-only and the other one is defined. > >> /// > >> @@ -956,6 +1026,31 @@ has_class_decl_only_def_change(const class_or_union_sptr& first, > >> return (f->get_is_declaration_only() != s->get_is_declaration_only()); > > > > Same here on the return statement. > > Fixed. > > [...] > > >> +bool > >> +has_enum_decl_only_def_change(const enum_type_decl_sptr& first, > >> + const enum_type_decl_sptr& second) > >> +{ > >> + if (!first || !second) > >> + return false; > >> + > >> + enum_type_decl_sptr f = look_through_decl_only_enum(first); > >> + enum_type_decl_sptr s = look_through_decl_only_enum(second); > >> + > >> + if (f->get_qualified_name() != s->get_qualified_name()) > >> + return false; > >> + > >> + return (f->get_is_declaration_only() != s->get_is_declaration_only()); > > > > And again. > > Fixed. > > [...] > > >> @@ -3423,7 +3427,9 @@ struct decl_base::priv > >> is_artificial_(false), > >> has_anonymous_parent_(false), > >> context_(), > >> - visibility_(VISIBILITY_DEFAULT) > >> + visibility_(VISIBILITY_DEFAULT), > >> + naked_definition_of_declaration_(), > >> + is_declaration_only_() > > > > Would be clearer to say (false). > > Fixed. > > >> {} > >> > >> priv(interned_string name, const location& locus, > >> @@ -3434,7 +3440,9 @@ struct decl_base::priv > >> name_(name), > >> qualified_name_(name), > >> linkage_name_(linkage_name), > >> - visibility_(vis) > >> + visibility_(vis), > >> + naked_definition_of_declaration_(), > >> + is_declaration_only_() > > > > Same here. > > Fixed. > > >> { > >> is_anonymous_ = name_.empty(); > >> has_anonymous_parent_ = false; > >> @@ -3446,7 +3454,9 @@ struct decl_base::priv > >> has_anonymous_parent_(false), > >> location_(l), > >> context_(), > >> - visibility_(VISIBILITY_DEFAULT) > >> + visibility_(VISIBILITY_DEFAULT), > >> + naked_definition_of_declaration_(), > >> + is_declaration_only_() > > > > And again. > > Fixed. > > [...] > > >> +/// Set a flag saying if the @ref enum_type_decl is a declaration-only > >> +/// @ref enum_type_decl. > >> +/// > >> +/// @param f true if the @ref enum_type_decl is a decalaration-only > > > > Typo: decalaration / declaration. > > Fixed. > > [...] > > >> +/// Test if a type is a enum. This function looks through typedefs. > > > > Typo: a enum / an enum. > > Fixed. > > [...] > > >> +/// Test if a type is a enum. This function looks through typedefs. > > > > Same typo. > > Fixed. > > >> +/// > >> +/// @parm t the type to consider. > >> +/// > >> +/// @return the enum_decl if @p t is a enum_decl or null otherwise. > > > > Technically a typo: a enum_decl / an enum_decl. > > I'm not sure how it will render if you @ref the types. > > Fixed. > > >> +enum_type_decl_sptr > >> +is_compatible_with_enum_type(const decl_base_sptr& t) > >> +{return is_compatible_with_enum_type(is_type(t));} > >> + > >> /// Test if a decl is an enum_type_decl > >> /// > >> /// @param d the decl to test for. > >> @@ -8270,24 +8386,19 @@ is_method_type(type_or_decl_base* t) > >> /// @param the_klass the class (or union) to consider. > > > > Parameter is the_class. > > Fixed. > > >> /// > >> /// @return either the definition of the class, or the class itself. > >> +class_or_union* > >> +look_through_decl_only_class(class_or_union* the_class) > >> +{return is_class_or_union_type(look_through_decl_only(the_class));} > >> + > >> +/// If a class (or union) is a decl-only class, get its definition. > >> +/// Otherwise, just return the initial class. > >> +/// > >> +/// @param the_klass the class (or union) to consider. > > > > Same here. > > Fixed. > > [...] > > > >> +decl_base_sptr > >> +look_through_decl_only(const decl_base& d) > >> +{ > >> + decl_base_sptr decl; > >> + if (d.get_is_declaration_only()) > >> + decl = d.get_definition_of_declaration(); > >> + > >> + if (!decl) > >> + return decl; > >> + > >> + while (decl > >> + && decl->get_is_declaration_only() > >> + && decl->get_definition_of_declaration()) > >> + decl = decl->get_definition_of_declaration(); > >> + > >> + ABG_ASSERT(decl); > >> + return decl; > > > > I had a suspicion that this code could be simplified a while ago. > > > > You should be able to simplify it to (something like): > > > > look_through_decl_only_class(class_or_union_sptr klass) > > { > > if (!klass) > > return klass; > > while (klass->get_is_declaration_only() > > && klass->get_definition_of_declaration()) > > klass = klass->get_definition_of_declaration(); > > return klass; > > } > > > > This is two things: > > 1. The function is simpler if it takes a (shared) pointer argument. > > You probably don't need the other overload. > > Actually, I prefer keeping the function that takes reference. It's > reused in the overload that takes a pointer. Also, I have some > test/play programs on the side that use types instantiated on the stack > etc and that make use of these. So they are useful in general, I think. > > > 2. You don't need to retest decl on every loop or assert it at the > > end, just check once at the top as the loop condition preserves the > > invariant. > > Yes, you are correct. I have made this change in the updated patch. > Thanks. > > [...] > > [...] > > >> +/// Look into a given corpus to find the enum type*s* that have a > >> +/// given qualified name. > >> +/// > >> +/// @param qualified_name the qualified name of the type to look for. > >> +/// > >> +/// @param corp the corpus to look into. > >> +/// > >> +/// @return the vector of enum types that which name is @p qualified_name. > > > > Suggest: "that which name is" -> "named" (or "which have the name") > > (and again, below) > > Of course. Fixed. > > [...] > > Please find below an updated patch that is present in my updated > dodji/incomp-enum branch. > > Thanks. > > > From 377b577cbbdc313e78b58631f5fb9bcc2c913a25 Mon Sep 17 00:00:00 2001 > From: Giuliano Procida <gprocida@google.com> > Date: Wed, 10 Jun 2020 12:59:35 +0100 > Subject: [PATCH 1/4] Support incomplete enums in core and diff code. > > This is an initial implementation of the support for incomplete, also > known as forward-declared, enum types. I've not made any attempt to > refactor or share logic with the struct/union code. > > * include/abg-comp-filter.h (has_decl_only_def_change) : Declare > New function. > * src/abg-comp-filter.cc (there_is_a_decl_only_enum): Define new > static function and ... > (type_size_changed): ... use it here. > (has_decl_only_def_change): Define new function and ... > (categorize_harm{less, ful}_diff_node): ... use it here. > * include/abg-fwd.h (enums_type, decl_base_wptr): Declare new > typedefs. > (look_through_decl_only_class): Declare new overload for > class_or_union*. > (is_compatible_with_enum_type, is_compatible_with_enum_type) > (look_through_decl_only, lookup_enum_types, lookup_enum_types): > Declare new functions. > * include/abg-ir.h (decl_base::{get_is_declaration_only, > set_is_declaration_only, set_definition_of_declaration, > get_definition_of_declaration, > get_naked_definition_of_declaration}): Declare new member > functions. They were moved here from the class_or_union class. > (class_or_union::{get_earlier_declaration, > set_earlier_declaration, get_definition_of_declaration, > set_definition_of_declaration, > get_naked_definition_of_declaration, get_is_declaration_only, > set_is_declaration_only}): Remove these member functions. > * src/abg-ir.cc (decl_base::priv::{declaration_, > definition_of_declaration_, naked_definition_of_declaration_, > is_declaration_only_}): Define data members. Moved here from > class_or_union. > (decl_base::priv::priv): Adjust to initialize the new data > members. > (decl_base::{get_earlier_declaration, set_earlier_declaration, > get_definition_of_declaration, > get_naked_definition_of_declaration, get_is_declaration_only, > set_is_declaration_only, set_definition_of_declaration}): Define > member functions. > (operator|): In the overload for (change_kind, change_kind), > adjust the return type of the call to > decl_base::get_definition_of_declaration. > (look_through_decl_only): Define new function. > (look_through_decl_only_class): Adjust. > (look_through_decl_only_enum): Likewise. > (maybe_update_types_lookup_map<class_decl>): Adjust return type of > call to decl_base::get_definition_of_declaration. > (types_defined_same_linux_kernel_corpus_public): Use > look_through_decl_only_class rather than open coding it. > (class_or_union::priv::{declaration_, definition_of_declaration_, > naked_definition_of_declaration_, is_declaration_only_}): Remove > these data members. They are now carried by decl_base::priv. > (class_or_union::{g,s}et_alignment_in_bits): Adjust. > (class_or_union::{g,s}et_size_in_bits): Likewise. > (class_or_union::operator==): Likewise. > (equals): Adjust the overload for class_or_union. > (is_compatible_with_enum_type) > * src/abg-comparison.cc (try_to_diff<class_decl>): Adjust the > return type of decl_base::get_definition_of_declaration. > (leaf_diff_node_marker_visitor::visit_begin): Use > filtering::has_decl_only_def_change rather than > filtering::has_class_decl_only_def_change. Decl-only changes to > enums (or any other type really) will thus not be recorded as leaf > changes. > * src/abg-dwarf-reader.cc (get_scope_for_die): Adjust return type > of decl_base::get_definition_of_declaration. > * src/abg-default-reporter.cc (default_reporter::report): Report > enum decl-only <-> definition changes. > * src/abg-hash.cc (class_or_union::hash::operator()): In the > overload for class_or_union& adjust the return type for > decl_base::get_definition_of_declaration. > > Signed-off-by: Giuliano Procida <gprocida@google.com> > Signed-off-by: Dodji Seketeli <dodji@redhat.com> > --- > include/abg-comp-filter.h | 14 ++ > include/abg-fwd.h | 36 ++++ > include/abg-ir.h | 48 ++--- > src/abg-comp-filter.cc | 133 ++++++++++++- > src/abg-comparison.cc | 10 +- > src/abg-default-reporter.cc | 19 ++ > src/abg-dwarf-reader.cc | 3 +- > src/abg-hash.cc | 3 +- > src/abg-ir.cc | 472 +++++++++++++++++++++++++++----------------- > 9 files changed, 519 insertions(+), 219 deletions(-) > > diff --git a/include/abg-comp-filter.h b/include/abg-comp-filter.h > index 8113003..556bad4 100644 > --- a/include/abg-comp-filter.h > +++ b/include/abg-comp-filter.h > @@ -65,13 +65,27 @@ bool > is_decl_only_class_with_size_change(const diff *diff); > > bool > +has_decl_only_def_change(const decl_base_sptr& first, > + const decl_base_sptr& second); > + > +bool > +has_decl_only_def_change(const diff *d); > + > +bool > has_class_decl_only_def_change(const class_or_union_sptr& first, > const class_or_union_sptr& second); > > bool > +has_enum_decl_only_def_change(const enum_type_decl_sptr& first, > + const enum_type_decl_sptr& second); > + > +bool > has_class_decl_only_def_change(const diff *diff); > > bool > +has_enum_decl_only_def_change(const diff *diff); > + > +bool > has_basic_type_name_change(const diff *); > > bool > diff --git a/include/abg-fwd.h b/include/abg-fwd.h > index f23f4a4..bfd9f88 100644 > --- a/include/abg-fwd.h > +++ b/include/abg-fwd.h > @@ -155,6 +155,12 @@ class enum_type_decl; > /// Convenience typedef for shared pointer to a @ref enum_type_decl. > typedef shared_ptr<enum_type_decl> enum_type_decl_sptr; > > +/// Convenience typedef for a vector of @ref enum_type_decl_sptr > +typedef vector<enum_type_decl_sptr> enums_type; > + > +/// Convenience typedef for a weak pointer to a @ref decl_base. > +typedef weak_ptr<decl_base> decl_base_wptr; > + > class class_or_union; > > typedef shared_ptr<class_or_union> class_or_union_sptr; > @@ -424,6 +430,12 @@ typedef_decl* > is_typedef(type_base*); > > enum_type_decl_sptr > +is_compatible_with_enum_type(const type_base_sptr&); > + > +enum_type_decl_sptr > +is_compatible_with_enum_type(const decl_base_sptr&); > + > +enum_type_decl_sptr > is_enum_type(const type_or_decl_base_sptr&); > > const enum_type_decl* > @@ -513,6 +525,24 @@ look_through_decl_only_class(const class_or_union&); > class_or_union_sptr > look_through_decl_only_class(class_or_union_sptr); > > +class_or_union* > +look_through_decl_only_class(class_or_union*); > + > +enum_type_decl_sptr > +look_through_decl_only_enum(const enum_type_decl&); > + > +enum_type_decl_sptr > +look_through_decl_only_enum(enum_type_decl_sptr); > + > +decl_base_sptr > +look_through_decl_only(const decl_base&); > + > +decl_base* > +look_through_decl_only(decl_base*); > + > +decl_base_sptr > +look_through_decl_only(const decl_base_sptr&); > + > var_decl* > is_var_decl(const type_or_decl_base*); > > @@ -1085,6 +1115,12 @@ lookup_enum_type(const string&, const corpus&); > enum_type_decl_sptr > lookup_enum_type(const interned_string&, const corpus&); > > +const type_base_wptrs_type* > +lookup_enum_types(const interned_string&, const corpus&); > + > +const type_base_wptrs_type* > +lookup_enum_types(const string&, const corpus&); > + > enum_type_decl_sptr > lookup_enum_type_per_location(const interned_string&, const corpus&); > > diff --git a/include/abg-ir.h b/include/abg-ir.h > index c2b66c4..5b13dc9 100644 > --- a/include/abg-ir.h > +++ b/include/abg-ir.h > @@ -1553,6 +1553,27 @@ public: > void > set_visibility(visibility v); > > + const decl_base_sptr > + get_earlier_declaration() const; > + > + void > + set_earlier_declaration(const decl_base_sptr&); > + > + const decl_base_sptr > + get_definition_of_declaration() const; > + > + void > + set_definition_of_declaration(const decl_base_sptr&); > + > + const decl_base* > + get_naked_definition_of_declaration() const; > + > + bool > + get_is_declaration_only() const; > + > + void > + set_is_declaration_only(bool f); > + > friend type_base_sptr > canonicalize(type_base_sptr); > > @@ -3776,27 +3797,6 @@ public: > void > set_naming_typedef(const typedef_decl_sptr&); > > - bool > - get_is_declaration_only() const; > - > - void > - set_is_declaration_only(bool f); > - > - void > - set_definition_of_declaration(class_or_union_sptr); > - > - const class_or_union_sptr > - get_definition_of_declaration() const; > - > - const class_or_union* > - get_naked_definition_of_declaration() const; > - > - decl_base_sptr > - get_earlier_declaration() const; > - > - void > - set_earlier_declaration(decl_base_sptr declaration); > - > void > insert_member_type(type_base_sptr t, > declarations::iterator before); > @@ -4020,12 +4020,6 @@ public: > class_decl(const environment* env, const string& name, bool is_struct, > bool is_declaration_only = true); > > - const class_decl_sptr > - get_definition_of_declaration() const; > - > - const class_decl* > - get_naked_definition_of_declaration() const; > - > virtual string > get_pretty_representation(bool internal = false, > bool qualified_name = true) const; > diff --git a/src/abg-comp-filter.cc b/src/abg-comp-filter.cc > index 702d223..0b0fbe4 100644 > --- a/src/abg-comp-filter.cc > +++ b/src/abg-comp-filter.cc > @@ -118,6 +118,25 @@ there_is_a_decl_only_class(const class_decl_sptr& class1, > return false; > } > > +/// Test if there is a enum that is declaration-only among the two > +/// enums in parameter. > +/// > +/// @param enum1 the first enum to consider. > +/// > +/// @param enum2 the second enum to consider. > +/// > +/// @return true if either enums are declaration-only, false > +/// otherwise. > +static bool > +there_is_a_decl_only_enum(const enum_type_decl_sptr& enum1, > + const enum_type_decl_sptr& enum2) > +{ > + if ((enum1 && enum1->get_is_declaration_only()) > + || (enum2 && enum2->get_is_declaration_only())) > + return true; > + return false; > +} > + > /// Test if the diff involves a declaration-only class. > /// > /// @param diff the class diff to consider. > @@ -146,7 +165,9 @@ type_size_changed(const type_base_sptr f, const type_base_sptr s) > || f->get_size_in_bits() == 0 > || s->get_size_in_bits() == 0 > || there_is_a_decl_only_class(is_compatible_with_class_type(f), > - is_compatible_with_class_type(s))) > + is_compatible_with_class_type(s)) > + || there_is_a_decl_only_enum(is_compatible_with_enum_type(f), > + is_compatible_with_enum_type(s))) > return false; > > return f->get_size_in_bits() != s->get_size_in_bits(); > @@ -893,10 +914,8 @@ is_decl_only_class_with_size_change(const class_or_union_sptr& first, > if (!first || !second) > return false; > > - class_or_union_sptr f = > - look_through_decl_only_class(first); > - class_or_union_sptr s = > - look_through_decl_only_class(second); > + class_or_union_sptr f = look_through_decl_only_class(first); > + class_or_union_sptr s = look_through_decl_only_class(second); > > return is_decl_only_class_with_size_change(*f, *s); > } > @@ -929,6 +948,57 @@ is_decl_only_class_with_size_change(const diff *diff) > return is_decl_only_class_with_size_change(f, s); > } > > +/// Test if two @ref decl_base_sptr are different just by the > +/// fact that one is decl-only and the other one is defined. > +/// > +/// @param first the first decl to consider. > +/// > +/// @param second the second decl to consider. > +/// > +/// @return true iff the two arguments are different just by the fact > +/// that one is decl-only and the other one is defined. > +bool > +has_decl_only_def_change(const decl_base_sptr& first, > + const decl_base_sptr& second) > +{ > + if (!first || !second) > + return false; > + > + decl_base_sptr f = > + look_through_decl_only(first); > + decl_base_sptr s = > + look_through_decl_only(second); > + > + if (f->get_qualified_name() != s->get_qualified_name()) > + return false; > + > + return f->get_is_declaration_only() != s->get_is_declaration_only(); > +} > + > +/// Test if a diff carries a change in which the two decls are > +/// different by the fact that one is a decl-only and the other one is > +/// defined. > +/// > +/// @param diff the diff node to consider. > +/// > +/// @return true if the diff carries a change in which the two decls > +/// are different by the fact that one is a decl-only and the other > +/// one is defined. > +bool > +has_decl_only_def_change(const diff *d) > +{ > + if (!d) > + return false; > + > + decl_base_sptr f = > + look_through_decl_only(is_decl(d->first_subject())); > + decl_base_sptr s = > + look_through_decl_only(is_decl(d->second_subject())); > + > + return has_decl_only_def_change(f, s); > +} > + > + > /// Test if two @ref class_or_union_sptr are different just by the > /// fact that one is decl-only and the other one is defined. > /// > @@ -953,7 +1023,32 @@ has_class_decl_only_def_change(const class_or_union_sptr& first, > if (f->get_qualified_name() != s->get_qualified_name()) > return false; > > - return (f->get_is_declaration_only() != s->get_is_declaration_only()); > + return f->get_is_declaration_only() != s->get_is_declaration_only(); > +} > + > +/// Test if two @ref enum_sptr are different just by the > +/// fact that one is decl-only and the other one is defined. > +/// > +/// @param first the first enum to consider. > +/// > +/// @param second the second enum to consider. > +/// > +/// @return true iff the two arguments are different just by the fact > +/// that one is decl-only and the other one is defined. > +bool > +has_enum_decl_only_def_change(const enum_type_decl_sptr& first, > + const enum_type_decl_sptr& second) > +{ > + if (!first || !second) > + return false; > + > + enum_type_decl_sptr f = look_through_decl_only_enum(first); > + enum_type_decl_sptr s = look_through_decl_only_enum(second); > + > + if (f->get_qualified_name() != s->get_qualified_name()) > + return false; > + > + return f->get_is_declaration_only() != s->get_is_declaration_only(); > } > > /// Test if a class_or_union_diff carries a change in which the two > @@ -980,6 +1075,28 @@ has_class_decl_only_def_change(const diff *diff) > return has_class_decl_only_def_change(f, s); > } > > +/// Test if a enum_diff carries a change in which the two enums are > +/// different by the fact that one is a decl-only and the other one is > +/// defined. > +/// > +/// @param diff the diff node to consider. > +/// > +/// @return true if the enum_diff carries a change in which the two > +/// enums are different by the fact that one is a decl-only and the > +/// other one is defined. > +bool > +has_enum_decl_only_def_change(const diff *diff) > +{ > + const enum_diff *d = dynamic_cast<const enum_diff*>(diff); > + if (!d) > + return false; > + > + enum_type_decl_sptr f = look_through_decl_only_enum(d->first_enum()); > + enum_type_decl_sptr s = look_through_decl_only_enum(d->second_enum()); > + > + return has_enum_decl_only_def_change(f, s); > +} > + > /// Test if a diff node carries a basic type name change. > /// > /// @param d the diff node to consider. > @@ -1517,7 +1634,8 @@ categorize_harmless_diff_node(diff *d, bool pre) > decl_base_sptr f = is_decl(d->first_subject()), > s = is_decl(d->second_subject()); > > - if (has_class_decl_only_def_change(d)) > + if (has_class_decl_only_def_change(d) > + || has_enum_decl_only_def_change(d)) > category |= TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY; > > if (access_changed(f, s)) > @@ -1608,6 +1726,7 @@ categorize_harmful_diff_node(diff *d, bool pre) > // > // TODO: be more specific -- not all size changes are harmful. > if (!has_class_decl_only_def_change(d) > + && !has_enum_decl_only_def_change(d) > && (type_size_changed(f, s) > || data_member_offset_changed(f, s) > || non_static_data_member_type_size_changed(f, s) > diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc > index d0f1d21..b6f065f 100644 > --- a/src/abg-comparison.cc > +++ b/src/abg-comparison.cc > @@ -2827,13 +2827,15 @@ try_to_diff<class_decl>(const type_or_decl_base_sptr first, > > if (f->get_is_declaration_only()) > { > - class_decl_sptr f2 = f->get_definition_of_declaration(); > + class_decl_sptr f2 = > + is_class_type (f->get_definition_of_declaration()); > if (f2) > f = f2; > } > if (s->get_is_declaration_only()) > { > - class_decl_sptr s2 = s->get_definition_of_declaration(); > + class_decl_sptr s2 = > + is_class_type(s->get_definition_of_declaration()); > if (s2) > s = s2; > } > @@ -10953,8 +10955,8 @@ struct leaf_diff_node_marker_visitor : public diff_node_visitor > // typedef change which underlying type is an anonymous > // struct/union. > && !is_anonymous_class_or_union_diff(d) > - // Don't show decl-only-ness changes of classes either. > - && !filtering::has_class_decl_only_def_change(d) > + // Don't show decl-only-ness changes either. > + && !filtering::has_decl_only_def_change(d) > // Sometime, we can encounter artifacts of bogus DWARF that > // yield a diff node for a decl-only class (and empty class > // with the is_declaration flag set) that carries a non-zero > diff --git a/src/abg-default-reporter.cc b/src/abg-default-reporter.cc > index 2acb695..cbf8c2b 100644 > --- a/src/abg-default-reporter.cc > +++ b/src/abg-default-reporter.cc > @@ -99,6 +99,25 @@ default_reporter::report(const enum_diff& d, ostream& out, > enum_type_decl_sptr first = d.first_enum(), second = d.second_enum(); > > const diff_context_sptr& ctxt = d.context(); > + > + // Report enum decl-only <-> definition changes. > + if (ctxt->get_allowed_category() & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY) > + if (filtering::has_enum_decl_only_def_change(first, second)) > + { > + string was = > + first->get_is_declaration_only() > + ? " was a declaration-only enum type" > + : " was a defined enum type"; > + > + string is_now = > + second->get_is_declaration_only() > + ? " and is now a declaration-only enum type" > + : " and is now a defined enum type"; > + > + out << indent << "enum type " << name << was << is_now << "\n"; > + return; > + } > + > report_name_size_and_alignment_changes(first, second, ctxt, > out, indent); > maybe_report_diff_for_member(first, second, ctxt, out, indent); > diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc > index ba4e750..db43aa7 100644 > --- a/src/abg-dwarf-reader.cc > +++ b/src/abg-dwarf-reader.cc > @@ -12315,7 +12315,8 @@ get_scope_for_die(read_context& ctxt, > class_decl_sptr cl = dynamic_pointer_cast<class_decl>(d); > if (cl && cl->get_is_declaration_only()) > { > - scope_decl_sptr scop (cl->get_definition_of_declaration()); > + scope_decl_sptr scop = > + dynamic_pointer_cast<scope_decl>(cl->get_definition_of_declaration()); > if (scop) > s = scop; > else > diff --git a/src/abg-hash.cc b/src/abg-hash.cc > index c1cdc57..5d2861f 100644 > --- a/src/abg-hash.cc > +++ b/src/abg-hash.cc > @@ -635,7 +635,8 @@ class_or_union::hash::operator()(const class_or_union& t) const > if (t.get_is_declaration_only()) > { > ABG_ASSERT(t.get_definition_of_declaration()); > - size_t v = operator()(*t.get_definition_of_declaration()); > + size_t v = operator() > + (*is_class_or_union_type(t.get_definition_of_declaration())); > return v; > } > > diff --git a/src/abg-ir.cc b/src/abg-ir.cc > index a434ec6..15bf124 100644 > --- a/src/abg-ir.cc > +++ b/src/abg-ir.cc > @@ -3416,6 +3416,10 @@ struct decl_base::priv > interned_string scoped_name_; > interned_string linkage_name_; > visibility visibility_; > + decl_base_sptr declaration_; > + decl_base_wptr definition_of_declaration_; > + decl_base* naked_definition_of_declaration_; > + bool is_declaration_only_; > > priv() > : in_pub_sym_tab_(false), > @@ -3423,7 +3427,9 @@ struct decl_base::priv > is_artificial_(false), > has_anonymous_parent_(false), > context_(), > - visibility_(VISIBILITY_DEFAULT) > + visibility_(VISIBILITY_DEFAULT), > + naked_definition_of_declaration_(), > + is_declaration_only_(false) > {} > > priv(interned_string name, const location& locus, > @@ -3434,7 +3440,9 @@ struct decl_base::priv > name_(name), > qualified_name_(name), > linkage_name_(linkage_name), > - visibility_(vis) > + visibility_(vis), > + naked_definition_of_declaration_(), > + is_declaration_only_(false) > { > is_anonymous_ = name_.empty(); > has_anonymous_parent_ = false; > @@ -3446,7 +3454,9 @@ struct decl_base::priv > has_anonymous_parent_(false), > location_(l), > context_(), > - visibility_(VISIBILITY_DEFAULT) > + visibility_(VISIBILITY_DEFAULT), > + naked_definition_of_declaration_(), > + is_declaration_only_(false) > {} > > ~priv() > @@ -3881,6 +3891,80 @@ const interned_string& > decl_base::get_scoped_name() const > {return priv_->scoped_name_;} > > +/// If this @ref decl_base is a definition, get its earlier > +/// declaration. > +/// > +/// @return the earlier declaration of the class, if any. > +const decl_base_sptr > +decl_base::get_earlier_declaration() const > +{return priv_->declaration_;} > + > +/// set the earlier declaration of this @ref decl_base definition. > +/// > +/// @param d the earlier declaration to set. Note that it's set only > +/// if it's a pure declaration. > +void > +decl_base::set_earlier_declaration(const decl_base_sptr& d) > +{ > + if (d && d->get_is_declaration_only()) > + priv_->declaration_ = d; > +} > + > + > +/// If this @ref decl_base is declaration-only, get its definition, if > +/// any. > +/// > +/// @return the definition of this decl-only @ref decl_base. > +const decl_base_sptr > +decl_base::get_definition_of_declaration() const > +{return priv_->definition_of_declaration_.lock();} > + > +/// If this @ref decl_base is declaration-only, get its definition, > +/// if any. > +/// > +/// Note that this function doesn't return a smart pointer, but rather > +/// the underlying pointer managed by the smart pointer. So it's as > +/// fast as possible. This getter is to be used in code paths that > +/// are proven to be performance hot spots; especially, when comparing > +/// sensitive types like enums, classes or unions. Those are compared > +/// extremely frequently and thus, their access to the definition of > +/// declaration must be fast. > +/// > +/// @return the definition of the declaration. > +const decl_base* > +decl_base::get_naked_definition_of_declaration() const > +{return priv_->naked_definition_of_declaration_;} > + > +/// Test if a @ref decl_base is a declaration-only decl. > +/// > +/// @return true iff the current @ref decl_base is declaration-only. > +bool > +decl_base::get_is_declaration_only() const > +{return priv_->is_declaration_only_;} > + > +/// Set a flag saying if the @ref enum_type_decl is a declaration-only > +/// @ref enum_type_decl. > +/// > +/// @param f true if the @ref enum_type_decl is a declaration-only > +/// @ref enum_type_decl. > +void > +decl_base::set_is_declaration_only(bool f) > +{ > + bool update_types_lookup_map = !f && priv_->is_declaration_only_; > + > + priv_->is_declaration_only_ = f; > + > + if (update_types_lookup_map) > + if (scope_decl* s = get_scope()) > + { > + scope_decl::declarations::iterator i; > + if (s->find_iterator_for_member(this, i)) > + maybe_update_types_lookup_map(*i); > + else > + ABG_ASSERT_NOT_REACHED; > + } > +} > + > change_kind > operator|(change_kind l, change_kind r) > { > @@ -4236,7 +4320,7 @@ operator!=(const type_base_sptr& l, const type_base_sptr& r) > > /// Tests if a declaration has got a scope. > /// > -/// @param d the decalaration to consider. > +/// @param d the declaration to consider. > /// > /// @return true if the declaration has got a scope, false otherwise. > bool > @@ -4245,7 +4329,7 @@ has_scope(const decl_base& d) > > /// Tests if a declaration has got a scope. > /// > -/// @param d the decalaration to consider. > +/// @param d the declaration to consider. > /// > /// @return true if the declaration has got a scope, false otherwise. > bool > @@ -6686,7 +6770,7 @@ get_location(const decl_base_sptr& decl) > if (class_or_union_sptr c = is_class_or_union_type(decl)) > if (c->get_is_declaration_only() && c->get_definition_of_declaration()) > { > - c = c->get_definition_of_declaration(); > + c = is_class_or_union_type(c->get_definition_of_declaration()); > loc = c->get_location(); > } > } > @@ -7925,6 +8009,40 @@ typedef_decl* > is_typedef(type_base* t) > {return dynamic_cast<typedef_decl*>(t);} > > +/// Test if a type is an enum. This function looks through typedefs. > +/// > +/// @parm t the type to consider. > +/// > +/// @return the enum_decl if @p t is an @ref enum_decl or null > +/// otherwise. > +enum_type_decl_sptr > +is_compatible_with_enum_type(const type_base_sptr& t) > +{ > + if (!t) > + return enum_type_decl_sptr(); > + > + // Normally we should strip typedefs entirely, but this is > + // potentially costly, especially on binaries with huge changesets > + // like the Linux Kernel. So we just get the leaf types for now. > + // > + // Maybe there should be an option by which users accepts to pay the > + // CPU usage toll in exchange for finer filtering? > + > + // type_base_sptr ty = strip_typedef(t); > + type_base_sptr ty = peel_typedef_type(t);; > + return is_enum_type(ty); > +} > + > +/// Test if a type is an enum. This function looks through typedefs. > +/// > +/// @parm t the type to consider. > +/// > +/// @return the enum_decl if @p t is an @ref enum_decl or null > +/// otherwise. > +enum_type_decl_sptr > +is_compatible_with_enum_type(const decl_base_sptr& t) > +{return is_compatible_with_enum_type(is_type(t));} > + > /// Test if a decl is an enum_type_decl > /// > /// @param d the decl to test for. > @@ -8267,27 +8385,22 @@ is_method_type(type_or_decl_base* t) > /// If a class (or union) is a decl-only class, get its definition. > /// Otherwise, just return the initial class. > /// > -/// @param the_klass the class (or union) to consider. > +/// @param the_class the class (or union) to consider. > +/// > +/// @return either the definition of the class, or the class itself. > +class_or_union* > +look_through_decl_only_class(class_or_union* the_class) > +{return is_class_or_union_type(look_through_decl_only(the_class));} > + > +/// If a class (or union) is a decl-only class, get its definition. > +/// Otherwise, just return the initial class. > +/// > +/// @param the_class the class (or union) to consider. > /// > /// @return either the definition of the class, or the class itself. > class_or_union_sptr > look_through_decl_only_class(const class_or_union& the_class) > -{ > - class_or_union_sptr klass; > - if (the_class.get_is_declaration_only()) > - klass = the_class.get_definition_of_declaration(); > - > - if (!klass) > - return klass; > - > - while (klass > - && klass->get_is_declaration_only() > - && klass->get_definition_of_declaration()) > - klass = klass->get_definition_of_declaration(); > - > - ABG_ASSERT(klass); > - return klass; > -} > +{return is_class_or_union_type(look_through_decl_only(the_class));} > > /// If a class (or union) is a decl-only class, get its definition. > /// Otherwise, just return the initial class. > @@ -8297,13 +8410,84 @@ look_through_decl_only_class(const class_or_union& the_class) > /// @return either the definition of the class, or the class itself. > class_or_union_sptr > look_through_decl_only_class(class_or_union_sptr klass) > +{return is_class_or_union_type(look_through_decl_only(klass));} > + > +/// If an enum is a decl-only enum, get its definition. > +/// Otherwise, just return the initial enum. > +/// > +/// @param the_enum the enum to consider. > +/// > +/// @return either the definition of the enum, or the enum itself. > +enum_type_decl_sptr > +look_through_decl_only_enum(const enum_type_decl& the_enum) > +{return is_enum_type(look_through_decl_only(the_enum));} > + > +/// If an enum is a decl-only enum, get its definition. > +/// Otherwise, just return the initial enum. > +/// > +/// @param enom the enum to consider. > +/// > +/// @return either the definition of the enum, or the enum itself. > +enum_type_decl_sptr > +look_through_decl_only_enum(enum_type_decl_sptr enom) > +{return is_enum_type(look_through_decl_only(enom));} > + > +/// If a decl is decl-only get its definition. Otherwise, just return nil. > +/// > +/// @param d the decl to consider. > +/// > +/// @return either the definition of the decl, or nil. > +decl_base_sptr > +look_through_decl_only(const decl_base& d) > +{ > + decl_base_sptr decl; > + if (d.get_is_declaration_only()) > + decl = d.get_definition_of_declaration(); > + > + if (!decl) > + return decl; > + > + while (decl->get_is_declaration_only() > + && decl->get_definition_of_declaration()) > + decl = decl->get_definition_of_declaration(); > + > + ABG_ASSERT(decl); The assert is still here (and redundant - to be honest, the compiler may be able to work this out for itself). I didn't spot anything else, so all good. Regards, Giuliano. > + return decl; > +} > + > +/// If a decl is decl-only enum, get its definition. Otherwise, just > +/// return the initial decl. > +/// > +/// @param d the decl to consider. > +/// > +/// @return either the definition of the enum, or the decl itself. > +decl_base* > +look_through_decl_only(decl_base* d) > +{ > + if (!d) > + return d; > + > + decl_base* result = look_through_decl_only(*d).get(); > + if (!result) > + result = d; > + > + return result; > +} > + > +/// If a decl is decl-only get its definition. Otherwise, just return nil. > +/// > +/// @param d the decl to consider. > +/// > +/// @return either the definition of the decl, or nil. > +decl_base_sptr > +look_through_decl_only(const decl_base_sptr& d) > { > - if (!klass) > - return klass; > + if (!d) > + return d; > > - class_or_union_sptr result = look_through_decl_only_class(*klass); > + decl_base_sptr result = look_through_decl_only(*d); > if (!result) > - result = klass; > + result = d; > > return result; > } > @@ -8784,7 +8968,7 @@ lookup_union_type_per_location(const string& loc, const corpus& corp) > return lookup_union_type_per_location(env->intern(loc), corp); > } > > -/// Lookup a enum type from a translation unit. > +/// Lookup an enum type from a translation unit. > /// > /// This is done by looking the type up in the type map that is > /// maintained in the translation unit. So this is as fast as > @@ -8802,7 +8986,7 @@ lookup_enum_type(const interned_string& type_name, const translation_unit& tu) > tu.get_types().enum_types()); > } > > -/// Lookup a enum type from a translation unit. > +/// Lookup an enum type from a translation unit. > /// > /// This is done by looking the type up in the type map that is > /// maintained in the translation unit. So this is as fast as > @@ -10004,7 +10188,7 @@ lookup_class_type(const interned_string& qualified_name, const corpus& corp) > /// > /// @param corp the corpus to look into. > /// > -/// @return the vector of class types that which name is @p qualified_name. > +/// @return the vector of class types named @p qualified_name. > const type_base_wptrs_type * > lookup_class_types(const interned_string& qualified_name, const corpus& corp) > { > @@ -10103,7 +10287,7 @@ lookup_union_type(const string& type_name, const corpus& corp) > return lookup_union_type(s, corp); > } > > -/// Look into a given corpus to find a enum type which has the same > +/// Look into a given corpus to find an enum type which has the same > /// qualified name as a given enum type. > /// > /// If the per-corpus type map is non-empty (because the corpus allows > @@ -10166,6 +10350,37 @@ lookup_enum_type(const interned_string& qualified_name, const corpus& corp) > return result; > } > > +/// Look into a given corpus to find the enum type*s* that have a > +/// given qualified name. > +/// > +/// @param qualified_name the qualified name of the type to look for. > +/// > +/// @param corp the corpus to look into. > +/// > +/// @return the vector of enum types that which name is @p qualified_name. > +const type_base_wptrs_type * > +lookup_enum_types(const interned_string& qualified_name, const corpus& corp) > +{ > + const istring_type_base_wptrs_map_type& m = corp.get_types().enum_types(); > + > + return lookup_types_in_map(qualified_name, m); > +} > + > +/// Look into a given corpus to find the enum type*s* that have a > +/// given qualified name. > +/// > +/// @param qualified_name the qualified name of the type to look for. > +/// > +/// @param corp the corpus to look into. > +/// > +/// @return the vector of enum types that which name is @p qualified_name. > +const type_base_wptrs_type* > +lookup_enum_types(const string& qualified_name, const corpus& corp) > +{ > + interned_string s = corp.get_environment()->intern(qualified_name); > + return lookup_enum_types(s, corp); > +} > + > /// Look up an @ref enum_type_decl from a given corpus, by its location. > /// > /// @param loc the location to consider. > @@ -10767,7 +10982,8 @@ maybe_update_types_lookup_map<class_decl>(const class_decl_sptr& class_type, > bool update_qname_map = true; > if (type->get_is_declaration_only()) > { > - if (class_decl_sptr def = class_type->get_definition_of_declaration()) > + if (class_decl_sptr def = > + is_class_type(class_type->get_definition_of_declaration())) > type = def; > else > update_qname_map = false; > @@ -11683,10 +11899,8 @@ types_defined_same_linux_kernel_corpus_public(const type_base& t1, > > // Look through declaration-only types. That is, get the associated > // definition type. > - if (c1 && c1->get_is_declaration_only()) > - c1 = c1->get_definition_of_declaration().get(); > - if (c2 && c2->get_is_declaration_only()) > - c2 = c2->get_definition_of_declaration().get(); > + c1 = look_through_decl_only_class(c1); > + c2 = look_through_decl_only_class(c2); > > if (c1 && c2) > { > @@ -12079,6 +12293,23 @@ canonicalize(type_base_sptr t) > return canonical; > } > > + > +/// Set the definition of this declaration-only @ref decl_base. > +/// > +/// @param d the new definition to set. > +void > +decl_base::set_definition_of_declaration(const decl_base_sptr& d) > +{ > + ABG_ASSERT(get_is_declaration_only()); > + priv_->definition_of_declaration_ = d; > + priv_->definition_of_declaration_ = d; > + if (type_base *t = is_type(this)) > + if (type_base_sptr canonical_type = is_type(d)->get_canonical_type()) > + t->priv_->canonical_type = canonical_type; > + > + priv_->naked_definition_of_declaration_ = const_cast<decl_base*>(d.get()); > +} > + > /// The constructor of @ref type_base. > /// > /// @param s the size of the type, in bits. > @@ -14978,7 +15209,6 @@ class enum_type_decl::priv > priv(); > > public: > - > priv(type_base_sptr underlying_type, > enumerators& enumerators) > : underlying_type_(underlying_type), > @@ -17987,9 +18217,6 @@ function_decl::parameter::get_pretty_representation(bool internal, > struct class_or_union::priv > { > typedef_decl_wptr naming_typedef_; > - decl_base_sptr declaration_; > - class_or_union_wptr definition_of_declaration_; > - class_or_union* naked_definition_of_declaration_; > member_types member_types_; > data_members data_members_; > data_members non_static_data_members_; > @@ -18001,21 +18228,16 @@ struct class_or_union::priv > string_mem_fn_ptr_map_type signature_2_mem_fn_map_; > member_function_templates member_function_templates_; > member_class_templates member_class_templates_; > - bool is_declaration_only_; > > priv() > - : naked_definition_of_declaration_(), > - is_declaration_only_(false) > {} > > priv(class_or_union::member_types& mbr_types, > class_or_union::data_members& data_mbrs, > class_or_union::member_functions& mbr_fns) > - : naked_definition_of_declaration_(), > - member_types_(mbr_types), > + : member_types_(mbr_types), > data_members_(data_mbrs), > - member_functions_(mbr_fns), > - is_declaration_only_(false) > + member_functions_(mbr_fns) > { > for (data_members::const_iterator i = data_members_.begin(); > i != data_members_.end(); > @@ -18024,11 +18246,6 @@ struct class_or_union::priv > non_static_data_members_.push_back(*i); > } > > - priv(bool is_declaration_only) > - : naked_definition_of_declaration_(), > - is_declaration_only_(is_declaration_only) > - {} > - > /// Mark a class or union or union as being currently compared using > /// the class_or_union== operator. > /// > @@ -18244,8 +18461,10 @@ class_or_union::class_or_union(const environment* env, const string& name, > decl_base(env, name, location(), name), > type_base(env, 0, 0), > scope_type_decl(env, name, 0, 0, location()), > - priv_(new priv(is_declaration_only)) > -{} > + priv_(new priv) > +{ > + set_is_declaration_only(is_declaration_only); > +} > > /// This implements the ir_traversable_base::traverse pure virtual > /// function. > @@ -18465,7 +18684,8 @@ size_t > class_or_union::get_alignment_in_bits() const > { > if (get_is_declaration_only() && get_definition_of_declaration()) > - return get_definition_of_declaration()->get_alignment_in_bits(); > + return is_class_or_union_type > + (get_definition_of_declaration())->get_alignment_in_bits(); > > return type_base::get_alignment_in_bits(); > } > @@ -18480,7 +18700,8 @@ void > class_or_union::set_alignment_in_bits(size_t a) > { > if (get_is_declaration_only() && get_definition_of_declaration()) > - get_definition_of_declaration()->set_alignment_in_bits(a); > + is_class_or_union_type > + (get_definition_of_declaration()) ->set_alignment_in_bits(a); > else > type_base::set_alignment_in_bits(a); > } > @@ -18495,7 +18716,8 @@ void > class_or_union::set_size_in_bits(size_t s) > { > if (get_is_declaration_only() && get_definition_of_declaration()) > - get_definition_of_declaration()->set_size_in_bits(s); > + is_class_or_union_type > + (get_definition_of_declaration())->set_size_in_bits(s); > else > type_base::set_size_in_bits(s); > } > @@ -18510,42 +18732,12 @@ size_t > class_or_union::get_size_in_bits() const > { > if (get_is_declaration_only() && get_definition_of_declaration()) > - return get_definition_of_declaration()->get_size_in_bits(); > + return is_class_or_union_type > + (get_definition_of_declaration())->get_size_in_bits(); > > return type_base::get_size_in_bits(); > } > > -/// Test if a @ref class_or_union is a declaration-only @ref > -/// class_or_union. > -/// > -/// @return true iff the current @ref class_or_union is a > -/// declaration-only @ref class_or_union. > -bool > -class_or_union::get_is_declaration_only() const > -{return priv_->is_declaration_only_;} > - > -/// Set a flag saying if the @ref class_or_union is a declaration-only > -/// @ref class_or_union. > -/// > -/// @param f true if the @ref class_or_union is a decalaration-only > -/// @ref class_or_union. > -void > -class_or_union::set_is_declaration_only(bool f) > -{ > - bool update_types_lookup_map = !f && priv_->is_declaration_only_; > - > - priv_->is_declaration_only_ = f; > - > - if (update_types_lookup_map) > - if (scope_decl* s = get_scope()) > - { > - declarations::iterator i; > - if (s->find_iterator_for_member(this, i)) > - maybe_update_types_lookup_map(*i); > - else > - ABG_ASSERT_NOT_REACHED; > - } > -} > > /// Getter for the naming typedef of the current class. > /// > @@ -18577,64 +18769,6 @@ class_or_union::set_naming_typedef(const typedef_decl_sptr& typedef_type) > priv_->naming_typedef_ = typedef_type; > } > > -/// Set the definition of this declaration-only @ref class_or_union. > -/// > -/// @param d the new definition to set. > -void > -class_or_union::set_definition_of_declaration(class_or_union_sptr d) > -{ > - ABG_ASSERT(get_is_declaration_only()); > - priv_->definition_of_declaration_ = d; > - if (d->get_canonical_type()) > - type_base::priv_->canonical_type = d->get_canonical_type(); > - > - priv_->naked_definition_of_declaration_ = d.get(); > -} > - > -/// If this @ref class_or_union_sptr is declaration-only, get its > -/// definition, if any. > -/// > -/// @return the definition of this decl-only class. > -const class_or_union_sptr > -class_or_union::get_definition_of_declaration() const > -{return priv_->definition_of_declaration_.lock();} > - > -/// If this @ref class_or_union is declaration-only, get its > -/// definition, if any. > -/// > -/// Note that this function doesn't return a smart pointer, but rather > -/// the underlying pointer managed by the smart pointer. So it's as > -/// fast as possible. This getter is to be used in code paths that > -/// are proven to be performance hot spots; especially, when comparing > -/// sensitive types like class or unions. Those are compared > -/// extremely frequently and thus, their access to the definition of > -/// declaration must be fast. > -/// > -/// @return the definition of the class. > -const class_or_union* > -class_or_union::get_naked_definition_of_declaration() const > -{return priv_->naked_definition_of_declaration_;} > - > -/// If this @ref class_or_union_sptr is a definitin, get its earlier > -/// declaration. > -/// > -/// @return the earlier declaration of the class, if any. > -decl_base_sptr > -class_or_union::get_earlier_declaration() const > -{return priv_->declaration_;} > - > -/// set the earlier declaration of this @ref class_or_union definition. > -/// > -/// @param declaration the earlier declaration to set. Note that it's > -/// set only if it's a pure declaration. > -void > -class_or_union::set_earlier_declaration(decl_base_sptr declaration) > -{ > - class_or_union_sptr cl = dynamic_pointer_cast<class_or_union>(declaration); > - if (cl && cl->get_is_declaration_only()) > - priv_->declaration_ = declaration; > -} > - > /// Get the member types of this @ref class_or_union. > /// > /// @return a vector of the member types of this ref class_or_union. > @@ -19082,15 +19216,16 @@ class_or_union::operator==(const decl_base& other) const > if (!canonical_type > && get_is_declaration_only() > && get_naked_definition_of_declaration()) > - canonical_type = > - get_naked_definition_of_declaration()->get_naked_canonical_type(); > + canonical_type = is_class_or_union_type > + (get_naked_definition_of_declaration())->get_naked_canonical_type(); > > // Likewise for the other class. > if (!other_canonical_type > && op->get_is_declaration_only() > && op->get_naked_definition_of_declaration()) > other_canonical_type = > - op->get_naked_definition_of_declaration()->get_naked_canonical_type(); > + is_class_or_union_type > + (op->get_naked_definition_of_declaration())->get_naked_canonical_type(); > > if (canonical_type && other_canonical_type) > return canonical_type == other_canonical_type; > @@ -19161,11 +19296,11 @@ equals(const class_or_union& l, const class_or_union& r, change_kind* k) > if (l_is_decl_only || r_is_decl_only) > { > const class_or_union* def1 = l_is_decl_only > - ? l.get_naked_definition_of_declaration() > + ? is_class_or_union_type(l.get_naked_definition_of_declaration()) > : &l; > > const class_or_union* def2 = r_is_decl_only > - ? r.get_naked_definition_of_declaration() > + ? is_class_or_union_type(r.get_naked_definition_of_declaration()) > : &r; > > if (!def1 || !def2) > @@ -19784,30 +19919,6 @@ class_decl::on_canonical_type_set() > sort_virtual_member_functions(i->second); > } > > -/// If this @ref class_decl is declaration-only, get its definition, > -/// if any. > -/// > -/// @return the definition of the class. > -const class_decl_sptr > -class_decl::get_definition_of_declaration() const > -{return is_class_type(class_or_union::get_definition_of_declaration());} > - > -/// If this @ref class_decl is declaration-only, get its definition, > -/// if any. > -/// > -/// Note that this function doesn't return a smart pointer, but rather > -/// the underlying pointer managed by the smart pointer. So it's as > -/// fast as possible. This getter is to be used in code paths that > -/// are proven to be performance hot spots; especially, when comparing > -/// sensitive types like class or unions. Those are compared > -/// extremely frequently and thus, their access to the definition of > -/// declaration must be fast. > -/// > -/// @return the definition of the class. > -const class_decl* > -class_decl::get_naked_definition_of_declaration() const > -{return is_class_type(class_or_union::get_naked_definition_of_declaration());} > - > /// Set the "is-struct" flag of the class. > /// > /// @param f the new value of the flag. > @@ -20938,14 +21049,16 @@ class_decl::operator==(const decl_base& other) const > && get_is_declaration_only() > && get_naked_definition_of_declaration()) > canonical_type = > - get_naked_definition_of_declaration()->get_naked_canonical_type(); > + is_class_type > + (get_naked_definition_of_declaration())->get_naked_canonical_type(); > > // Likewise for the other class. > if (!other_canonical_type > && op->get_is_declaration_only() > && op->get_naked_definition_of_declaration()) > other_canonical_type = > - op->get_naked_definition_of_declaration()->get_naked_canonical_type(); > + is_class_type > + (op->get_naked_definition_of_declaration())->get_naked_canonical_type(); > > if (canonical_type && other_canonical_type) > return canonical_type == other_canonical_type; > @@ -23035,7 +23148,8 @@ hash_type(const type_base *t) > // The is a declaration-only class, so it has no canonical > // type; but then it's class definition has one. Let's > // use that one. > - return hash_type(cl->get_naked_definition_of_declaration()); > + return hash_type > + (is_class_type(cl->get_naked_definition_of_declaration())); > else > { > // The class really has no canonical type, let's use the > -- > 1.8.3.1 > > > -- > Dodji
Giuliano Procida <gprocida@google.com> a écrit: [...] >> +/// If a decl is decl-only get its definition. Otherwise, just return nil. >> +/// >> +/// @param d the decl to consider. >> +/// >> +/// @return either the definition of the decl, or nil. >> +decl_base_sptr >> +look_through_decl_only(const decl_base& d) >> +{ >> + decl_base_sptr decl; >> + if (d.get_is_declaration_only()) >> + decl = d.get_definition_of_declaration(); >> + >> + if (!decl) >> + return decl; >> + >> + while (decl->get_is_declaration_only() >> + && decl->get_definition_of_declaration()) >> + decl = decl->get_definition_of_declaration(); >> + >> + ABG_ASSERT(decl); > > The assert is still here (and redundant - to be honest, the compiler > may be able to work this out for itself). Pff, right. I removed it now, thanks. > I didn't spot anything else, so all good. Thanks. I've just applied the series to master then. Cheers,
diff --git a/include/abg-comp-filter.h b/include/abg-comp-filter.h index 81130033..3b845088 100644 --- a/include/abg-comp-filter.h +++ b/include/abg-comp-filter.h @@ -68,9 +68,16 @@ bool has_class_decl_only_def_change(const class_or_union_sptr& first, const class_or_union_sptr& second); +bool +has_enum_decl_only_def_change(const enum_type_decl_sptr& first, + const enum_type_decl_sptr& second); + bool has_class_decl_only_def_change(const diff *diff); +bool +has_enum_decl_only_def_change(const diff *diff); + bool has_basic_type_name_change(const diff *); diff --git a/include/abg-fwd.h b/include/abg-fwd.h index 999b071b..73d809ab 100644 --- a/include/abg-fwd.h +++ b/include/abg-fwd.h @@ -155,6 +155,12 @@ class enum_type_decl; /// Convenience typedef for shared pointer to a @ref enum_type_decl. typedef shared_ptr<enum_type_decl> enum_type_decl_sptr; +/// Convenience typedef for a vector of @ref enum_type_decl_sptr +typedef vector<enum_type_decl_sptr> enums_type; + +/// Convenience typedef for a weak pointer to a @ref enum_type_decl. +typedef weak_ptr<enum_type_decl> enum_type_decl_wptr; + class class_or_union; typedef shared_ptr<class_or_union> class_or_union_sptr; @@ -423,6 +429,12 @@ is_typedef(const type_base*); typedef_decl* is_typedef(type_base*); +enum_type_decl_sptr +is_compatible_with_enum_type(const type_base_sptr&); + +enum_type_decl_sptr +is_compatible_with_enum_type(const decl_base_sptr&); + enum_type_decl_sptr is_enum_type(const type_or_decl_base_sptr&); @@ -513,6 +525,12 @@ look_through_decl_only_class(const class_or_union&); class_or_union_sptr look_through_decl_only_class(class_or_union_sptr); +enum_type_decl_sptr +look_through_decl_only_enum(const enum_type_decl&); + +enum_type_decl_sptr +look_through_decl_only_enum(enum_type_decl_sptr); + var_decl* is_var_decl(const type_or_decl_base*); @@ -1085,6 +1103,12 @@ lookup_enum_type(const string&, const corpus&); enum_type_decl_sptr lookup_enum_type(const interned_string&, const corpus&); +const type_base_wptrs_type* +lookup_enum_types(const interned_string&, const corpus&); + +const type_base_wptrs_type* +lookup_enum_types(const string&, const corpus&); + enum_type_decl_sptr lookup_enum_type_per_location(const interned_string&, const corpus&); diff --git a/include/abg-ir.h b/include/abg-ir.h index ebcc4b81..2114e27b 100644 --- a/include/abg-ir.h +++ b/include/abg-ir.h @@ -2497,6 +2497,21 @@ public: enumerators& get_enumerators(); + bool + get_is_declaration_only() const; + + void + set_is_declaration_only(bool f); + + void + set_definition_of_declaration(enum_type_decl_sptr); + + const enum_type_decl_sptr + get_definition_of_declaration() const; + + const enum_type_decl* + get_naked_definition_of_declaration() const; + virtual string get_pretty_representation(bool internal = false, bool qualified_name = true) const; diff --git a/src/abg-comp-filter.cc b/src/abg-comp-filter.cc index 81548427..70858f27 100644 --- a/src/abg-comp-filter.cc +++ b/src/abg-comp-filter.cc @@ -118,6 +118,25 @@ there_is_a_decl_only_class(const class_decl_sptr& class1, return false; } +/// Test if there is a enum that is declaration-only among the two +/// enums in parameter. +/// +/// @param enum1 the first enum to consider. +/// +/// @param enum2 the second enum to consider. +/// +/// @return true if either enums are declaration-only, false +/// otherwise. +static bool +there_is_a_decl_only_enum(const enum_type_decl_sptr& enum1, + const enum_type_decl_sptr& enum2) +{ + if ((enum1 && enum1->get_is_declaration_only()) + || (enum2 && enum2->get_is_declaration_only())) + return true; + return false; +} + /// Test if the diff involves a declaration-only class. /// /// @param diff the class diff to consider. @@ -146,7 +165,9 @@ type_size_changed(const type_base_sptr f, const type_base_sptr s) || f->get_size_in_bits() == 0 || s->get_size_in_bits() == 0 || there_is_a_decl_only_class(is_compatible_with_class_type(f), - is_compatible_with_class_type(s))) + is_compatible_with_class_type(s)) + || there_is_a_decl_only_enum(is_compatible_with_enum_type(f), + is_compatible_with_enum_type(s))) return false; return f->get_size_in_bits() != s->get_size_in_bits(); @@ -956,6 +977,31 @@ has_class_decl_only_def_change(const class_or_union_sptr& first, return (f->get_is_declaration_only() != s->get_is_declaration_only()); } +/// Test if two @ref enum_sptr are different just by the +/// fact that one is decl-only and the other one is defined. +/// +/// @param first the first enum to consider. +/// +/// @param second the second enum to consider. +/// +/// @return true iff the two arguments are different just by the fact +/// that one is decl-only and the other one is defined. +bool +has_enum_decl_only_def_change(const enum_type_decl_sptr& first, + const enum_type_decl_sptr& second) +{ + if (!first || !second) + return false; + + enum_type_decl_sptr f = look_through_decl_only_enum(first); + enum_type_decl_sptr s = look_through_decl_only_enum(second); + + if (f->get_qualified_name() != s->get_qualified_name()) + return false; + + return (f->get_is_declaration_only() != s->get_is_declaration_only()); +} + /// Test if a class_or_union_diff carries a change in which the two /// classes are different by the fact that one is a decl-only and the /// other one is defined. @@ -980,6 +1026,28 @@ has_class_decl_only_def_change(const diff *diff) return has_class_decl_only_def_change(f, s); } +/// Test if a enum_diff carries a change in which the two enums are +/// different by the fact that one is a decl-only and the other one is +/// defined. +/// +/// @param diff the diff node to consider. +/// +/// @return true if the enum_diff carries a change in which the two +/// enums are different by the fact that one is a decl-only and the +/// other one is defined. +bool +has_enum_decl_only_def_change(const diff *diff) +{ + const enum_diff *d = dynamic_cast<const enum_diff*>(diff); + if (!d) + return false; + + enum_type_decl_sptr f = look_through_decl_only_enum(d->first_enum()); + enum_type_decl_sptr s = look_through_decl_only_enum(d->second_enum()); + + return has_enum_decl_only_def_change(f, s); +} + /// Test if a diff node carries a basic type name change. /// /// @param d the diff node to consider. @@ -1517,7 +1585,8 @@ categorize_harmless_diff_node(diff *d, bool pre) decl_base_sptr f = is_decl(d->first_subject()), s = is_decl(d->second_subject()); - if (has_class_decl_only_def_change(d)) + if (has_class_decl_only_def_change(d) + || has_enum_decl_only_def_change(d)) category |= TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY; if (access_changed(f, s)) @@ -1608,6 +1677,7 @@ categorize_harmful_diff_node(diff *d, bool pre) // // TODO: be more specific -- not all size changes are harmful. if (!has_class_decl_only_def_change(d) + && !has_enum_decl_only_def_change(d) && (type_size_changed(f, s) || data_member_offset_changed(f, s) || non_static_data_member_type_size_changed(f, s) diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc index f77799f2..21cab0e7 100644 --- a/src/abg-comparison.cc +++ b/src/abg-comparison.cc @@ -10962,7 +10962,9 @@ struct leaf_diff_node_marker_visitor : public diff_node_visitor // with the is_declaration flag set) that carries a non-zero // size! And of course at some point that non-zero size // changes. We need to be able to detect that. - && !filtering::is_decl_only_class_with_size_change(d)) + && !filtering::is_decl_only_class_with_size_change(d) + // Don't show decl-only-ness changes of enums. + && !filtering::has_enum_decl_only_def_change(d)) { diff_context_sptr ctxt = d->context(); const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get(); diff --git a/src/abg-default-reporter.cc b/src/abg-default-reporter.cc index 2acb6954..cbf8c2bc 100644 --- a/src/abg-default-reporter.cc +++ b/src/abg-default-reporter.cc @@ -99,6 +99,25 @@ default_reporter::report(const enum_diff& d, ostream& out, enum_type_decl_sptr first = d.first_enum(), second = d.second_enum(); const diff_context_sptr& ctxt = d.context(); + + // Report enum decl-only <-> definition changes. + if (ctxt->get_allowed_category() & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY) + if (filtering::has_enum_decl_only_def_change(first, second)) + { + string was = + first->get_is_declaration_only() + ? " was a declaration-only enum type" + : " was a defined enum type"; + + string is_now = + second->get_is_declaration_only() + ? " and is now a declaration-only enum type" + : " and is now a defined enum type"; + + out << indent << "enum type " << name << was << is_now << "\n"; + return; + } + report_name_size_and_alignment_changes(first, second, ctxt, out, indent); maybe_report_diff_for_member(first, second, ctxt, out, indent); diff --git a/src/abg-ir.cc b/src/abg-ir.cc index 5cc39f59..9f4890e8 100644 --- a/src/abg-ir.cc +++ b/src/abg-ir.cc @@ -7924,6 +7924,38 @@ typedef_decl* is_typedef(type_base* t) {return dynamic_cast<typedef_decl*>(t);} +/// Test if a type is a enum. This function looks through typedefs. +/// +/// @parm t the type to consider. +/// +/// @return the enum_decl if @p t is a enum_decl or null otherwise. +enum_type_decl_sptr +is_compatible_with_enum_type(const type_base_sptr& t) +{ + if (!t) + return enum_type_decl_sptr(); + + // Normally we should strip typedefs entirely, but this is + // potentially costly, especially on binaries with huge changesets + // like the Linux Kernel. So we just get the leaf types for now. + // + // Maybe there should be an option by which users accepts to pay the + // CPU usage toll in exchange for finer filtering? + + // type_base_sptr ty = strip_typedef(t); + type_base_sptr ty = peel_typedef_type(t);; + return is_enum_type(ty); +} + +/// Test if a type is a enum. This function looks through typedefs. +/// +/// @parm t the type to consider. +/// +/// @return the enum_decl if @p t is a enum_decl or null otherwise. +enum_type_decl_sptr +is_compatible_with_enum_type(const decl_base_sptr& t) +{return is_compatible_with_enum_type(is_type(t));} + /// Test if a decl is an enum_type_decl /// /// @param d the decl to test for. @@ -8307,6 +8339,50 @@ look_through_decl_only_class(class_or_union_sptr klass) return result; } +/// If a enum is a decl-only enum, get its definition. +/// Otherwise, just return the initial enum. +/// +/// @param the_enum the enum to consider. +/// +/// @return either the definition of the enum, or the enum itself. +enum_type_decl_sptr +look_through_decl_only_enum(const enum_type_decl& the_enum) +{ + enum_type_decl_sptr enom; + if (the_enum.get_is_declaration_only()) + enom = the_enum.get_definition_of_declaration(); + + if (!enom) + return enom; + + while (enom + && enom->get_is_declaration_only() + && enom->get_definition_of_declaration()) + enom = enom->get_definition_of_declaration(); + + ABG_ASSERT(enom); + return enom; +} + +/// If a enum is a decl-only enum, get its definition. +/// Otherwise, just return the initial enum. +/// +/// @param enom the enum to consider. +/// +/// @return either the definition of the enum, or the enum itself. +enum_type_decl_sptr +look_through_decl_only_enum(enum_type_decl_sptr enom) +{ + if (!enom) + return enom; + + enum_type_decl_sptr result = look_through_decl_only_enum(*enom); + if (!result) + result = enom; + + return result; +} + /// Tests if a declaration is a variable declaration. /// /// @param decl the decl to test. @@ -10165,6 +10241,37 @@ lookup_enum_type(const interned_string& qualified_name, const corpus& corp) return result; } +/// Look into a given corpus to find the enum type*s* that have a +/// given qualified name. +/// +/// @param qualified_name the qualified name of the type to look for. +/// +/// @param corp the corpus to look into. +/// +/// @return the vector of enum types that which name is @p qualified_name. +const type_base_wptrs_type * +lookup_enum_types(const interned_string& qualified_name, const corpus& corp) +{ + const istring_type_base_wptrs_map_type& m = corp.get_types().enum_types(); + + return lookup_types_in_map(qualified_name, m); +} + +/// Look into a given corpus to find the enum type*s* that have a +/// given qualified name. +/// +/// @param qualified_name the qualified name of the type to look for. +/// +/// @param corp the corpus to look into. +/// +/// @return the vector of enum types that which name is @p qualified_name. +const type_base_wptrs_type* +lookup_enum_types(const string& qualified_name, const corpus& corp) +{ + interned_string s = corp.get_environment()->intern(qualified_name); + return lookup_enum_types(s, corp); +} + /// Look up an @ref enum_type_decl from a given corpus, by its location. /// /// @param loc the location to consider. @@ -14974,17 +15081,26 @@ class enum_type_decl::priv { type_base_sptr underlying_type_; enumerators enumerators_; + decl_base_sptr declaration_; + enum_type_decl_wptr definition_of_declaration_; + enum_type_decl* naked_definition_of_declaration_; + bool is_declaration_only_; friend class enum_type_decl; - priv(); - public: + priv() + : naked_definition_of_declaration_(), + is_declaration_only_(true) + {} + priv(type_base_sptr underlying_type, enumerators& enumerators) : underlying_type_(underlying_type), - enumerators_(enumerators) + enumerators_(enumerators), + naked_definition_of_declaration_(), + is_declaration_only_(false) {} }; // end class enum_type_decl::priv @@ -15040,6 +15156,80 @@ enum_type_decl::enumerators& enum_type_decl::get_enumerators() {return priv_->enumerators_;} +/// Set the definition of this declaration-only @ref enum_type_decl. +/// +/// @param d the new definition to set. +void +enum_type_decl::set_definition_of_declaration(enum_type_decl_sptr d) +{ + ABG_ASSERT(get_is_declaration_only()); + priv_->definition_of_declaration_ = d; + if (d->get_canonical_type()) + type_base::priv_->canonical_type = d->get_canonical_type(); + + priv_->naked_definition_of_declaration_ = d.get(); +} + +/// If this @ref enum_type_decl_sptr is declaration-only, get its +/// definition, if any. +/// +/// @return the definition of this decl-only enum. +const enum_type_decl_sptr +enum_type_decl::get_definition_of_declaration() const +{ + if (priv_->definition_of_declaration_.expired()) + return enum_type_decl_sptr(); + return enum_type_decl_sptr(priv_->definition_of_declaration_); +} + +/// If this @ref enum_type_decl is declaration-only, get its +/// definition, if any. +/// +/// Note that this function doesn't return a smart pointer, but rather +/// the underlying pointer managed by the smart pointer. So it's as +/// fast as possible. This getter is to be used in code paths that are +/// proven to be performance hot spots; especially, when comparing +/// sensitive types like enums. Those are compared extremely frequently +/// and thus, their access to the definition of declaration must be +/// fast. +/// +/// @return the definition of the enum. +const enum_type_decl* +enum_type_decl::get_naked_definition_of_declaration() const +{return priv_->naked_definition_of_declaration_;} + +/// Test if a @ref enum_type_decl is a declaration-only @ref +/// enum_type_decl. +/// +/// @return true iff the current @ref enum_type_decl is a +/// declaration-only @ref enum_type_decl. +bool +enum_type_decl::get_is_declaration_only() const +{return priv_->is_declaration_only_;} + +/// Set a flag saying if the @ref enum_type_decl is a declaration-only +/// @ref enum_type_decl. +/// +/// @param f true if the @ref enum_type_decl is a decalaration-only +/// @ref enum_type_decl. +void +enum_type_decl::set_is_declaration_only(bool f) +{ + bool update_types_lookup_map = !f && priv_->is_declaration_only_; + + priv_->is_declaration_only_ = f; + + if (update_types_lookup_map) + if (scope_decl* s = get_scope()) + { + scope_decl::declarations::iterator i; + if (s->find_iterator_for_member(this, i)) + maybe_update_types_lookup_map(*i); + else + ABG_ASSERT_NOT_REACHED; + } +} + /// Get the pretty representation of the current instance of @ref /// enum_type_decl. ///