From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [217.70.178.231]) by sourceware.org (Postfix) with ESMTPS id E7B77385E444 for ; Wed, 8 Jul 2020 09:22:18 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org E7B77385E444 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=seketeli.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=dodji@seketeli.org Received: from localhost (91-166-131-130.subs.proxad.net [91.166.131.130]) (Authenticated sender: dodji@seketeli.org) by relay11.mail.gandi.net (Postfix) with ESMTPSA id BC7EB100016; Wed, 8 Jul 2020 09:22:16 +0000 (UTC) Received: by localhost (Postfix, from userid 1000) id 17A861800867; Wed, 8 Jul 2020 11:22:15 +0200 (CEST) From: Dodji Seketeli To: Giuliano Procida Cc: libabigail@sourceware.org Subject: Re: [PATCH 06/11] Support incomplete enums in core and diff code. Organization: Me, myself and I References: <20200610115940.26035-1-gprocida@google.com> <20200610115940.26035-7-gprocida@google.com> <874kqkuc7h.fsf@seketeli.org> X-Operating-System: Red Hat Enterprise Linux Workstation 7.8 Beta X-URL: http://www.seketeli.net/~dodji Date: Wed, 08 Jul 2020 11:22:14 +0200 In-Reply-To: (Giuliano Procida's message of "Tue, 7 Jul 2020 09:23:32 +0100") Message-ID: <87y2nuqs3d.fsf@seketeli.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-8.5 required=5.0 tests=BAYES_00, GIT_PATCH_0, JMQ_SPF_NEUTRAL, KAM_DMARC_STATUS, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_PASS, TXREP, T_FILL_THIS_FORM_SHORT autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libabigail@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list of the Libabigail project List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 08 Jul 2020 09:22:24 -0000 Hello Giuliano, Giuliano Procida a =C3=A9crit: > 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 =3D >> + look_through_decl_only(first); >> + decl_base_sptr s =3D >> + look_through_decl_only(second); >> + >> + if (f->get_qualified_name() !=3D s->get_qualified_name()) >> + return false; >> + >> + return (f->get_is_declaration_only() !=3D 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_unio= n_sptr& first, >> return (f->get_is_declaration_only() !=3D 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 =3D look_through_decl_only_enum(first); >> + enum_type_decl_sptr s =3D look_through_decl_only_enum(second); >> + >> + if (f->get_qualified_name() !=3D s->get_qualified_name()) >> + return false; >> + >> + return (f->get_is_declaration_only() !=3D 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_ =3D name_.empty(); >> has_anonymous_parent_ =3D 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 =3D d.get_definition_of_declaration(); >> + >> + if (!decl) >> + return decl; >> + >> + while (decl >> + && decl->get_is_declaration_only() >> + && decl->get_definition_of_declaration()) >> + decl =3D 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 =3D 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_na= me. > > 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 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): 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=3D=3D): Likewise. (equals): Adjust the overload for class_or_union. (is_compatible_with_enum_type) * src/abg-comparison.cc (try_to_diff): 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 Signed-off-by: Dodji Seketeli --- 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); =20 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); =20 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); =20 bool +has_enum_decl_only_def_change(const diff *diff); + +bool has_basic_type_name_change(const diff *); =20 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_sptr; =20 +/// Convenience typedef for a vector of @ref enum_type_decl_sptr +typedef vector enums_type; + +/// Convenience typedef for a weak pointer to a @ref decl_base. +typedef weak_ptr decl_base_wptr; + class class_or_union; =20 typedef shared_ptr class_or_union_sptr; @@ -424,6 +430,12 @@ typedef_decl* is_typedef(type_base*); =20 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&); =20 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); =20 +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*); =20 @@ -1085,6 +1115,12 @@ lookup_enum_type(const string&, const corpus&); enum_type_decl_sptr lookup_enum_type(const interned_string&, const corpus&); =20 +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&); =20 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); =20 + 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); =20 @@ -3776,27 +3797,6 @@ public: void set_naming_typedef(const typedef_decl_sptr&); =20 - 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 =3D true); =20 - 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 =3D false, bool qualified_name =3D 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& clas= s1, return false; } =20 +/// 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_ba= se_sptr s) || f->get_size_in_bits() =3D=3D 0 || s->get_size_in_bits() =3D=3D 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; =20 return f->get_size_in_bits() !=3D s->get_size_in_bits(); @@ -893,10 +914,8 @@ is_decl_only_class_with_size_change(const class_or_uni= on_sptr& first, if (!first || !second) return false; =20 - class_or_union_sptr f =3D - look_through_decl_only_class(first); - class_or_union_sptr s =3D - look_through_decl_only_class(second); + class_or_union_sptr f =3D look_through_decl_only_class(first); + class_or_union_sptr s =3D look_through_decl_only_class(second); =20 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); } =20 +/// 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 =3D + look_through_decl_only(first); + decl_base_sptr s =3D + look_through_decl_only(second); + + if (f->get_qualified_name() !=3D s->get_qualified_name()) + return false; + + return f->get_is_declaration_only() !=3D 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 =3D + look_through_decl_only(is_decl(d->first_subject())); + decl_base_sptr s =3D + 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_s= ptr& first, if (f->get_qualified_name() !=3D s->get_qualified_name()) return false; =20 - return (f->get_is_declaration_only() !=3D s->get_is_declaration_only()); + return f->get_is_declaration_only() !=3D 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 =3D look_through_decl_only_enum(first); + enum_type_decl_sptr s =3D look_through_decl_only_enum(second); + + if (f->get_qualified_name() !=3D s->get_qualified_name()) + return false; + + return f->get_is_declaration_only() !=3D s->get_is_declaration_only(); } =20 /// 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); } =20 +/// 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 =3D dynamic_cast(diff); + if (!d) + return false; + + enum_type_decl_sptr f =3D look_through_decl_only_enum(d->first_enum()); + enum_type_decl_sptr s =3D 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 =3D is_decl(d->first_subject()), s =3D is_decl(d->second_subject()); =20 - if (has_class_decl_only_def_change(d)) + if (has_class_decl_only_def_change(d) + || has_enum_decl_only_def_change(d)) category |=3D TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY; =20 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(const type_or_decl_base_spt= r first, =20 if (f->get_is_declaration_only()) { - class_decl_sptr f2 =3D f->get_definition_of_declaration(); + class_decl_sptr f2 =3D + is_class_type (f->get_definition_of_declaration()); if (f2) f =3D f2; } if (s->get_is_declaration_only()) { - class_decl_sptr s2 =3D s->get_definition_of_declaration(); + class_decl_sptr s2 =3D + is_class_type(s->get_definition_of_declaration()); if (s2) s =3D 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& ou= t, enum_type_decl_sptr first =3D d.first_enum(), second =3D d.second_enum(); =20 const diff_context_sptr& ctxt =3D 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 =3D + first->get_is_declaration_only() + ? " was a declaration-only enum type" + : " was a defined enum type"; + + string is_now =3D + 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 =3D dynamic_pointer_cast(d); if (cl && cl->get_is_declaration_only()) { - scope_decl_sptr scop (cl->get_definition_of_declaration()); + scope_decl_sptr scop =3D + dynamic_pointer_cast(cl->get_definition_of_declaration()); if (scop) s =3D 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 =3D operator()(*t.get_definition_of_declaration()); + size_t v =3D operator() + (*is_class_or_union_type(t.get_definition_of_declaration())); return v; } =20 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_; =20 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) {} =20 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_ =3D name_.empty(); has_anonymous_parent_ =3D 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) {} =20 ~priv() @@ -3881,6 +3891,80 @@ const interned_string& decl_base::get_scoped_name() const {return priv_->scoped_name_;} =20 +/// 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_ =3D 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 =3D !f && priv_->is_declaration_only_; + + priv_->is_declaration_only_ =3D f; + + if (update_types_lookup_map) + if (scope_decl* s =3D 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!=3D(const type_base_sptr& l, const type_base= _sptr& r) =20 /// 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) =20 /// 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 =3D is_class_or_union_type(decl)) if (c->get_is_declaration_only() && c->get_definition_of_declaration()) { - c =3D c->get_definition_of_declaration(); + c =3D is_class_or_union_type(c->get_definition_of_declaration()); loc =3D c->get_location(); } } @@ -7925,6 +8009,40 @@ typedef_decl* is_typedef(type_base* t) {return dynamic_cast(t);} =20 +/// 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 =3D strip_typedef(t); + type_base_sptr ty =3D 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 =3D the_class.get_definition_of_declaration(); - - if (!klass) - return klass; - - while (klass - && klass->get_is_declaration_only() - && klass->get_definition_of_declaration()) - klass =3D klass->get_definition_of_declaration(); - - ABG_ASSERT(klass); - return klass; -} +{return is_class_or_union_type(look_through_decl_only(the_class));} =20 /// 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 =3D d.get_definition_of_declaration(); + + if (!decl) + return decl; + + while (decl->get_is_declaration_only() + && decl->get_definition_of_declaration()) + decl =3D 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 =3D look_through_decl_only(*d).get(); + if (!result) + result =3D 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; =20 - class_or_union_sptr result =3D look_through_decl_only_class(*klass); + decl_base_sptr result =3D look_through_decl_only(*d); if (!result) - result =3D klass; + result =3D d; =20 return result; } @@ -8784,7 +8968,7 @@ lookup_union_type_per_location(const string& loc, con= st corpus& corp) return lookup_union_type_per_location(env->intern(loc), corp); } =20 -/// 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, co= nst translation_unit& tu) tu.get_types().enum_types()); } =20 -/// 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& co= rp) { @@ -10103,7 +10287,7 @@ lookup_union_type(const string& type_name, const co= rpus& corp) return lookup_union_type(s, corp); } =20 -/// 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; } =20 +/// 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& cor= p) +{ + const istring_type_base_wptrs_map_type& m =3D corp.get_types().enum_type= s(); + + 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 =3D 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(const cla= ss_decl_sptr& class_type, bool update_qname_map =3D true; if (type->get_is_declaration_only()) { - if (class_decl_sptr def =3D class_type->get_definition_of_declaratio= n()) + if (class_decl_sptr def =3D + is_class_type(class_type->get_definition_of_declaration())) type =3D def; else update_qname_map =3D false; @@ -11683,10 +11899,8 @@ types_defined_same_linux_kernel_corpus_public(cons= t type_base& t1, =20 // Look through declaration-only types. That is, get the associated // definition type. - if (c1 && c1->get_is_declaration_only()) - c1 =3D c1->get_definition_of_declaration().get(); - if (c2 && c2->get_is_declaration_only()) - c2 =3D c2->get_definition_of_declaration().get(); + c1 =3D look_through_decl_only_class(c1); + c2 =3D look_through_decl_only_class(c2); =20 if (c1 && c2) { @@ -12079,6 +12293,23 @@ canonicalize(type_base_sptr t) return canonical; } =20 + +/// 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_ =3D d; + priv_->definition_of_declaration_ =3D d; + if (type_base *t =3D is_type(this)) + if (type_base_sptr canonical_type =3D is_type(d)->get_canonical_type()) + t->priv_->canonical_type =3D canonical_type; + + priv_->naked_definition_of_declaration_ =3D const_cast(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(); =20 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_; =20 priv() - : naked_definition_of_declaration_(), - is_declaration_only_(false) {} =20 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 =3D data_members_.begin(); i !=3D data_members_.end(); @@ -18024,11 +18246,6 @@ struct class_or_union::priv non_static_data_members_.push_back(*i); } =20 - 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=3D=3D 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); +} =20 /// 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(); =20 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(); =20 return type_base::get_size_in_bits(); } =20 -/// 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 =3D !f && priv_->is_declaration_only_; - - priv_->is_declaration_only_ =3D f; - - if (update_types_lookup_map) - if (scope_decl* s =3D get_scope()) - { - declarations::iterator i; - if (s->find_iterator_for_member(this, i)) - maybe_update_types_lookup_map(*i); - else - ABG_ASSERT_NOT_REACHED; - } -} =20 /// Getter for the naming typedef of the current class. /// @@ -18577,64 +18769,6 @@ class_or_union::set_naming_typedef(const typedef_d= ecl_sptr& typedef_type) priv_->naming_typedef_ =3D typedef_type; } =20 -/// 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_ =3D d; - if (d->get_canonical_type()) - type_base::priv_->canonical_type =3D d->get_canonical_type(); - - priv_->naked_definition_of_declaration_ =3D 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 =3D dynamic_pointer_cast(declarat= ion); - if (cl && cl->get_is_declaration_only()) - priv_->declaration_ =3D 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=3D=3D(const decl_base& o= ther) const if (!canonical_type && get_is_declaration_only() && get_naked_definition_of_declaration()) - canonical_type =3D - get_naked_definition_of_declaration()->get_naked_canonical_type(); + canonical_type =3D is_class_or_union_type + (get_naked_definition_of_declaration())->get_naked_canonical_type(); =20 // Likewise for the other class. if (!other_canonical_type && op->get_is_declaration_only() && op->get_naked_definition_of_declaration()) other_canonical_type =3D - op->get_naked_definition_of_declaration()->get_naked_canonical_type(= ); + is_class_or_union_type + (op->get_naked_definition_of_declaration())->get_naked_canonical_typ= e(); =20 if (canonical_type && other_canonical_type) return canonical_type =3D=3D other_canonical_type; @@ -19161,11 +19296,11 @@ equals(const class_or_union& l, const class_or_un= ion& r, change_kind* k) if (l_is_decl_only || r_is_decl_only) { const class_or_union* def1 =3D l_is_decl_only - ? l.get_naked_definition_of_declaration() + ? is_class_or_union_type(l.get_naked_definition_of_declaration()) : &l; =20 const class_or_union* def2 =3D r_is_decl_only - ? r.get_naked_definition_of_declaration() + ? is_class_or_union_type(r.get_naked_definition_of_declaration()) : &r; =20 if (!def1 || !def2) @@ -19784,30 +19919,6 @@ class_decl::on_canonical_type_set() sort_virtual_member_functions(i->second); } =20 -/// 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=3D=3D(const decl_base& other= ) const && get_is_declaration_only() && get_naked_definition_of_declaration()) canonical_type =3D - get_naked_definition_of_declaration()->get_naked_canonical_type(); + is_class_type + (get_naked_definition_of_declaration())->get_naked_canonical_type(); =20 // Likewise for the other class. if (!other_canonical_type && op->get_is_declaration_only() && op->get_naked_definition_of_declaration()) other_canonical_type =3D - op->get_naked_definition_of_declaration()->get_naked_canonical_type(= ); + is_class_type + (op->get_naked_definition_of_declaration())->get_naked_canonical_typ= e(); =20 if (canonical_type && other_canonical_type) return canonical_type =3D=3D 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 --=20 1.8.3.1 --=20 Dodji