From b1b69abd791d49e1ecb1a8532b3a14af8cfe7e9e Mon Sep 17 00:00:00 2001 From: Dodji Seketeli Date: Fri, 27 Jan 2023 15:58:37 +0100 Subject: [PATCH] suppression: Factorize out is_data_member_offset_in_range In preparation of subsequent changes, this patch factorizes a function is_data_member_offset_in_range() out of type_suppression::suppression(). This is useful to determine if a data member offset is within an "offset range" expressed by the type_suppression::insertion_range type. This function is useful to implement the offset_of_first_data_member_regexp and offset_of_last_data_member_regexp properties to come in subsequent patches. Please note that is_data_member_offset_in_range works on data members of unions and classes, not just on classes like what the original code of inside type_suppression::suppresses_diff was doing. This patch should not have any functional impact on the code. * include/abg-fwd.h (get_last_data_member) (get_next_data_member_offset): Declare functions. * src/abg-ir.cc (get_next_data_member): Add an overload for class_or_union and write the overload for class_or_union_sptr in term of the former. (get_last_data_member): Add overloads form class_or_union& and class_or_union*. Write the overload for class_or_union_sptr in terms of the one for class_or_union*. (get_next_data_member_offset): Add an overload for class_or_union* and write the overload for class_or_union_sptr in terms of the former. * include/abg-suppression.h (type_suppression::insertion_range::eval_boundary): Take a class_or_union* for the context, as opposed to a class_decl_sptr. This makes this static function work for unions as well. (is_data_member_offset_in_range): Declare new function. * src/abg-suppression.cc (type_suppression::suppression_diff): Factorize ... (is_data_member_offset_in_range): ... this function out. (type_suppression::insertion_range::eval_boundary): Adjust this to make it take a class_or_union* rather than a class_decl_sptr. Signed-off-by: Dodji Seketeli --- include/abg-fwd.h | 11 ++++ include/abg-suppression.h | 12 +++- src/abg-ir.cc | 57 +++++++++++++++++- src/abg-suppression.cc | 122 ++++++++++++++++++++------------------ 4 files changed, 138 insertions(+), 64 deletions(-) diff --git a/include/abg-fwd.h b/include/abg-fwd.h index 155642f0..4051fab5 100644 --- a/include/abg-fwd.h +++ b/include/abg-fwd.h @@ -655,6 +655,12 @@ is_data_member(const decl_base *); const var_decl_sptr get_next_data_member(const class_or_union_sptr&, const var_decl_sptr&); +var_decl_sptr +get_last_data_member(const class_or_union&); + +var_decl_sptr +get_last_data_member(const class_or_union*); + var_decl_sptr get_last_data_member(const class_or_union_sptr&); @@ -740,6 +746,11 @@ get_data_member_offset(const decl_base_sptr); uint64_t get_absolute_data_member_offset(const var_decl&); +bool +get_next_data_member_offset(const class_or_union*, + const var_decl_sptr&, + uint64_t&); + bool get_next_data_member_offset(const class_or_union_sptr&, const var_decl_sptr&, diff --git a/include/abg-suppression.h b/include/abg-suppression.h index 27f52110..b13bb9fb 100644 --- a/include/abg-suppression.h +++ b/include/abg-suppression.h @@ -346,9 +346,9 @@ public: create_fn_call_expr_boundary(const string&); static bool - eval_boundary(boundary_sptr boundary, - class_decl_sptr context, - uint64_t& value); + eval_boundary(const boundary_sptr boundary, + const class_or_union* context, + uint64_t& value); static bool boundary_value_is_end(uint64_t value); @@ -899,6 +899,12 @@ is_type_suppressed(const fe_iface& fe, const location& type_location, bool& type_is_private, bool require_drop_property = false); + +bool +is_data_member_offset_in_range(const var_decl_sptr&, + const type_suppression::insertion_range_sptr&, + const class_or_union*); + } // end namespace suppr diff --git a/src/abg-ir.cc b/src/abg-ir.cc index 321adbf5..ef19eb41 100644 --- a/src/abg-ir.cc +++ b/src/abg-ir.cc @@ -5752,7 +5752,7 @@ get_first_non_anonymous_data_member(const var_decl_sptr anon_dm) /// @return the data member that is located right after @p /// data_member. const var_decl_sptr -get_next_data_member(const class_or_union_sptr &klass, +get_next_data_member(const class_or_union *klass, const var_decl_sptr &data_member) { if (!klass ||!data_member) @@ -5773,12 +5773,40 @@ get_next_data_member(const class_or_union_sptr &klass, return var_decl_sptr(); } +/// In the context of a given class or union, this function returns +/// the data member that is located after a given data member. +/// +/// @param klass the class or union to consider. +/// +/// @param the data member to consider. +/// +/// @return the data member that is located right after @p +/// data_member. +const var_decl_sptr +get_next_data_member(const class_or_union_sptr& klass, + const var_decl_sptr &data_member) +{return get_next_data_member(klass.get(), data_member);} + +/// Get the last data member of a class type. +/// +/// @param klass the class type to consider. +var_decl_sptr +get_last_data_member(const class_or_union& klass) +{return klass.get_non_static_data_members().back();} + +/// Get the last data member of a class type. +/// +/// @param klass the class type to consider. +var_decl_sptr +get_last_data_member(const class_or_union* klass) +{return get_last_data_member(*klass);} + /// Get the last data member of a class type. /// /// @param klass the class type to consider. var_decl_sptr get_last_data_member(const class_or_union_sptr &klass) -{return klass->get_non_static_data_members().back();} +{return get_last_data_member(klass.get());} /// Test if a decl is an anonymous data member. /// @@ -6062,7 +6090,7 @@ get_data_member_offset(const decl_base_sptr d) /// @return true iff the data member coming right after @p dm was /// found. bool -get_next_data_member_offset(const class_or_union_sptr& klass, +get_next_data_member_offset(const class_or_union* klass, const var_decl_sptr& dm, uint64_t& offset) { @@ -6073,6 +6101,29 @@ get_next_data_member_offset(const class_or_union_sptr& klass, return true; } +/// Get the offset of the non-static data member that comes after a +/// given one. +/// +/// If there is no data member after after the one given to this +/// function (maybe because the given one is the last data member of +/// the class type) then the function return false. +/// +/// @param klass the class to consider. +/// +/// @param dm the data member before the one we want to retrieve. +/// +/// @param offset out parameter. This parameter is set by the +/// function to the offset of the data member that comes right after +/// the data member @p dm, iff the function returns true. +/// +/// @return true iff the data member coming right after @p dm was +/// found. +bool +get_next_data_member_offset(const class_or_union_sptr& klass, + const var_decl_sptr& dm, + uint64_t& offset) +{return get_next_data_member_offset(klass.get(), dm, offset);} + /// Get the absolute offset of a data member. /// /// If the data member is part of an anonymous data member then this diff --git a/src/abg-suppression.cc b/src/abg-suppression.cc index 5fcdef97..b596e0d5 100644 --- a/src/abg-suppression.cc +++ b/src/abg-suppression.cc @@ -865,65 +865,19 @@ type_suppression::suppresses_diff(const diff* diff) const const class_decl_sptr& first_type_decl = klass_diff->first_class_decl(); - for (string_decl_base_sptr_map::const_iterator m = - klass_diff->inserted_data_members().begin(); - m != klass_diff->inserted_data_members().end(); - ++m) + // All inserted data members must be in an allowed + // insertion range. + for (const auto& m : klass_diff->inserted_data_members()) { - decl_base_sptr member = m->second; - size_t dm_offset = get_data_member_offset(member); + decl_base_sptr member = m.second; bool matched = false; - for (insertion_ranges::const_iterator i = - get_data_member_insertion_ranges().begin(); - i != get_data_member_insertion_ranges().end(); - ++i) - { - type_suppression::insertion_range_sptr range = *i; - uint64_t range_begin_val = 0, range_end_val = 0; - if (!type_suppression::insertion_range::eval_boundary - (range->begin(), first_type_decl, range_begin_val)) - break; - if (!type_suppression::insertion_range::eval_boundary - (range->end(), first_type_decl, range_end_val)) - break; - - uint64_t range_begin = range_begin_val; - uint64_t range_end = range_end_val; - - if (insertion_range::boundary_value_is_end(range_begin) - && insertion_range::boundary_value_is_end(range_end)) - { - // This idiom represents the predicate - // "has_data_member_inserted_at = end" - if (dm_offset > - get_data_member_offset(get_last_data_member - (first_type_decl))) - { - // So the data member was added after - // last data member of the klass. That - // matches the suppr spec - // "has_data_member_inserted_at = end". - matched = true; - continue; - } - } - - if (range_begin > range_end) - // Wrong suppr spec. Ignore it. - continue; - - if (dm_offset < range_begin || dm_offset > range_end) - // The offset of the added data member doesn't - // match the insertion range specified. So - // the diff object won't be suppressed. - continue; - - // If we reached this point, then all the - // insertion range constraints have been - // satisfied. So + for (const auto& range : get_data_member_insertion_ranges()) + if (is_data_member_offset_in_range(is_var_decl(member), + range, + first_type_decl.get())) matched = true; - } + if (!matched) return false; } @@ -1404,9 +1358,9 @@ type_suppression::insertion_range::create_fn_call_expr_boundary(const string& s) /// @return true iff the evaluation was successful and @p value /// contains the resulting value. bool -type_suppression::insertion_range::eval_boundary(boundary_sptr boundary, - class_decl_sptr context, - uint64_t& value) +type_suppression::insertion_range::eval_boundary(const boundary_sptr boundary, + const class_or_union* context, + uint64_t& value) { if (integer_boundary_sptr b = is_integer_boundary(boundary)) { @@ -4962,5 +4916,57 @@ is_type_suppressed(const fe_iface& fe, return false; } +/// Test if a data memer offset is in a given insertion range. +/// +/// @param dm the data member to consider. +/// +/// @param range the insertion range to consider. +/// +/// @param the class (or union) type to consider as the context in +/// which to evaluate the insertion range denoted by @p range. +/// +/// @return true iff the offset of the data member @p dm is in the +/// insertion range @p range in the context of the type denoted by @p +/// context. +bool +is_data_member_offset_in_range(const var_decl_sptr& dm, + const type_suppression::insertion_range_sptr& range, + const class_or_union* context) +{ + ABG_ASSERT(dm && range && context); + + uint64_t range_begin = 0, range_end = 0; + if (!type_suppression::insertion_range::eval_boundary (range->begin(), + context, + range_begin)) + return false; + + if (!type_suppression::insertion_range::eval_boundary (range->end(), + context, + range_end)) + return false; + + if (range_begin > range_end) + // wrong range, ignore it. + return false; + + uint64_t dm_offset = get_data_member_offset(dm); + if (type_suppression::insertion_range::boundary_value_is_end(range_begin) + && type_suppression::insertion_range::boundary_value_is_end(range_end)) + { + // This idiom represents the predicate + // "has_data_member_inserted_at = end" + if (dm_offset > get_data_member_offset(get_last_data_member(context))) + return true; + return false; + } + + if (dm_offset < range_begin || dm_offset > range_end) + // The offset of the data member is outside the range. + return false; + + return true; +} + }// end namespace suppr } // end namespace abigail -- 2.34.1