[2/3] dwarf-reader: Remove redundant qualifiers from qualified types
Commit Message
Hello,
While looking at something else, I noticed that there are some
qualified types built from the DWARF debug info that read:
const volatile const int m[5]
That's a tree of (chained) qualified types that end up having some
redundant qualifiers. That IR tree might look like:
[C] --> [C|V] --> [int]
We want to edit that IR tree to make it look like:
[C] --> [V] --> [int]
And that would serialize as
const volatile int m[5]
This patch introduces the editing of the qualified type IR tree to
remove the redundant qualifiers, right after the IR is built from
DWARF.
* include/abg-fwd.h (strip_redundant_quals_from_underyling_types):
Declare new function.
* include/abg-ir.h (operator&=): Declare new binary operator for
qualified_type_def::CV and ...
* src/abg-ir.cc (+operator&=): ... define it here.
(strip_redundant_quals_from_underyling_types): Define new function
and ...
* src/abg-dwarf-reader.cc (maybe_strip_qualification): ... Use it
here.
* tests/data/test-abidiff-exit/qualifier-typedef-array-report-1.txt:
Adjust.
Signed-off-by: Dodji Seketeli <dodji@redhat.com>
Applied to master.
---
include/abg-fwd.h | 3 +
include/abg-ir.h | 3 +
src/abg-dwarf-reader.cc | 5 +-
src/abg-ir.cc | 115 ++++++++++++++++++
.../qualifier-typedef-array-report-1.txt | 40 +++---
5 files changed, 145 insertions(+), 21 deletions(-)
@@ -827,6 +827,9 @@ strip_typedef(const type_base_sptr);
decl_base_sptr
strip_useless_const_qualification(const qualified_type_def_sptr t);
+void
+strip_redundant_quals_from_underyling_types(const qualified_type_def_sptr&);
+
type_base_sptr
peel_typedef_type(const type_base_sptr&);
@@ -2243,6 +2243,9 @@ operator|(qualified_type_def::CV, qualified_type_def::CV);
qualified_type_def::CV&
operator|=(qualified_type_def::CV&, qualified_type_def::CV);
+qualified_type_def::CV&
+operator&=(qualified_type_def::CV&, qualified_type_def::CV);
+
qualified_type_def::CV
operator&(qualified_type_def::CV, qualified_type_def::CV);
@@ -13544,6 +13544,7 @@ maybe_strip_qualification(const qualified_type_def_sptr t,
decl_base_sptr result = t;
type_base_sptr u = t->get_underlying_type();
+ strip_redundant_quals_from_underyling_types(t);
result = strip_useless_const_qualification(t);
if (result.get() != t.get())
return result;
@@ -13590,6 +13591,7 @@ maybe_strip_qualification(const qualified_type_def_sptr t,
qualified_type_def::CV quals = qualified->get_cv_quals();
quals |= t->get_cv_quals();
qualified->set_cv_quals(quals);
+ strip_redundant_quals_from_underyling_types(qualified);
result = is_decl(u);
}
else
@@ -13598,6 +13600,7 @@ maybe_strip_qualification(const qualified_type_def_sptr t,
(new qualified_type_def(element_type,
t->get_cv_quals(),
t->get_location()));
+ strip_redundant_quals_from_underyling_types(qual_type);
add_decl_to_scope(qual_type, is_decl(element_type)->get_scope());
array->set_element_type(qual_type);
ctxt.schedule_type_for_late_canonicalization(is_type(qual_type));
@@ -15584,7 +15587,7 @@ build_ir_node_from_die(read_context& ctxt,
ctxt.associate_die_to_type(die, ty, where_offset);
result =
add_decl_to_scope(d, ctxt.cur_transl_unit()->get_global_scope());
- maybe_canonicalize_type(die, ctxt);
+ maybe_canonicalize_type(is_type(result), ctxt);
}
}
break;
@@ -6715,6 +6715,113 @@ strip_useless_const_qualification(const qualified_type_def_sptr t)
return result;
}
+/// Merge redundant qualifiers from a tree of qualified types.
+///
+/// Suppose a tree of qualified types leads to:
+///
+/// const virtual const restrict const int;
+///
+/// Suppose the IR tree of qualified types ressembles (with C meaning
+/// const, V meaning virtual and R meaning restrict):
+///
+/// [C|V]-->[C|R] -->[C] --> [int].
+///
+/// This function walks the IR and remove the redundant CV qualifiers
+/// so the IR becomes:
+///
+/// [C|V] --> [R] --> [] -->[int].
+///
+/// Note that the empty qualified type (noted []) represents a
+/// qualified type with no qualifier. It's rare, but it can exist.
+/// I've put it here just for the sake of example.
+///
+/// The resulting IR thus represents the (merged) type:
+///
+/// const virtual restrict int.
+///
+/// This function is a sub-routine of the overload @ref
+/// strip_useless_const_qualification which doesn't return any value.
+///
+/// @param t the qualified type to consider.
+///
+/// @param redundant_quals the (redundant) qualifiers to be removed
+/// from the qualifiers of the underlying types of @p t.
+///
+/// @return the underlying type of @p t which might have had its
+/// redundant qualifiers removed.
+static qualified_type_def_sptr
+strip_redundant_quals_from_underyling_types(const qualified_type_def_sptr& t,
+ qualified_type_def::CV redundant_quals)
+{
+ if (!t)
+ return t;
+
+ // We must NOT edit canonicalized types.
+ ABG_ASSERT(!t->get_canonical_type());
+
+ qualified_type_def_sptr underlying_qualified_type =
+ is_qualified_type(t->get_underlying_type());
+
+ // Let's build 'currated qualifiers' that are the qualifiers of the
+ // current type from which redundant qualifiers are removed.
+ qualified_type_def::CV currated_quals = t->get_cv_quals();
+
+ // Remove the redundant qualifiers from these currated qualifiers
+ currated_quals &= ~redundant_quals;
+ t->set_cv_quals(currated_quals);
+
+ // The redundant qualifiers, moving forward, is now the union of the
+ // previous set of redundant qualifiers and the currated qualifiers.
+ redundant_quals |= currated_quals;
+
+ qualified_type_def_sptr result = t;
+ if (underlying_qualified_type)
+ // Now remove the redundant qualifiers from the qualified types
+ // potentially carried by the underlying type.
+ result =
+ strip_redundant_quals_from_underyling_types(underlying_qualified_type,
+ redundant_quals);
+
+ return result;
+}
+
+/// Merge redundant qualifiers from a tree of qualified types.
+///
+/// Suppose a tree of qualified types leads to:
+///
+/// const virtual const restrict const int;
+///
+/// Suppose the IR tree of qualified types ressembles (with C meaning
+/// const, V meaning virtual and R meaning restrict):
+///
+/// [C|V]-->[C|R] -->[C] --> [int].
+///
+/// This function walks the IR and remove the redundant CV qualifiers
+/// so the IR becomes:
+///
+/// [C|V] --> [R] --> [] -->[int].
+///
+/// Note that the empty qualified type (noted []) represents a
+/// qualified type with no qualifier. It's rare, but it can exist.
+/// I've put it here just for the sake of example.
+///
+/// The resulting IR thus represents the (merged) type:
+///
+/// const virtual restrict int.
+///
+/// @param t the qualified type to consider. The IR below the
+/// argument to this parameter will be edited to remove redundant
+/// qualifiers where applicable.
+void
+strip_redundant_quals_from_underyling_types(const qualified_type_def_sptr& t)
+{
+ if (!t)
+ return;
+
+ qualified_type_def::CV redundant_quals = qualified_type_def::CV_NONE;
+ strip_redundant_quals_from_underyling_types(t, redundant_quals);
+}
+
/// Return the leaf underlying type node of a @ref typedef_decl node.
///
/// If the underlying type of a @ref typedef_decl node is itself a
@@ -15653,6 +15760,14 @@ operator|=(qualified_type_def::CV& l, qualified_type_def::CV r)
return l;
}
+/// Overloaded bitwise &= operator for cv qualifiers.
+qualified_type_def::CV&
+operator&=(qualified_type_def::CV& l, qualified_type_def::CV r)
+{
+ l = l & r;
+ return l;
+}
+
/// Overloaded bitwise AND operator for CV qualifiers.
qualified_type_def::CV
operator&(qualified_type_def::CV lhs, qualified_type_def::CV rhs)
@@ -47,39 +47,39 @@ Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
underlying type 'typedef A' at qualifier-typedef-array-v0.c:1:1 changed:
entity changed from 'typedef A' to compatible type 'void*[7]'
type of 'C v_c' changed:
- entity changed from 'typedef C' to compatible type 'const volatile void* const[7]'
+ entity changed from 'typedef C' to compatible type 'const volatile void*[7]'
array element type 'void* const' changed:
- 'void* const' changed to 'const volatile void* const'
- type name changed from 'void* const[7]' to 'const volatile void* const[7]'
+ 'void* const' changed to 'const volatile void*'
+ type name changed from 'void* const[7]' to 'const volatile void*[7]'
type size hasn't changed
type of 'C r_c' changed:
- entity changed from 'typedef C' to compatible type 'restrict const void* const[7]'
+ entity changed from 'typedef C' to compatible type 'restrict const void*[7]'
array element type 'void* const' changed:
- 'void* const' changed to 'restrict const void* const'
- type name changed from 'void* const[7]' to 'restrict const void* const[7]'
+ 'void* const' changed to 'restrict const void*'
+ type name changed from 'void* const[7]' to 'restrict const void*[7]'
type size hasn't changed
type of 'D v_d' changed:
- entity changed from 'typedef D' to compatible type 'const volatile void* const[7]'
+ entity changed from 'typedef D' to compatible type 'const volatile void*[7]'
array element type 'void* const' changed:
- 'void* const' changed to 'const volatile void* const'
- type name changed from 'void* const[7]' to 'const volatile void* const[7]'
+ 'void* const' changed to 'const volatile void*'
+ type name changed from 'void* const[7]' to 'const volatile void*[7]'
type size hasn't changed
type of 'D r_d' changed:
- entity changed from 'typedef D' to compatible type 'restrict const void* const[7]'
+ entity changed from 'typedef D' to compatible type 'restrict const void*[7]'
array element type 'void* const' changed:
- 'void* const' changed to 'restrict const void* const'
- type name changed from 'void* const[7]' to 'restrict const void* const[7]'
+ 'void* const' changed to 'restrict const void*'
+ type name changed from 'void* const[7]' to 'restrict const void*[7]'
type size hasn't changed
type of 'E r_e' changed:
- entity changed from 'typedef E' to compatible type 'restrict const volatile volatile void* const[7]'
- array element type 'const volatile void* const' changed:
- 'const volatile void* const' changed to 'restrict const volatile volatile void* const'
- type name changed from 'const volatile void* const[7]' to 'restrict const volatile volatile void* const[7]'
+ entity changed from 'typedef E' to compatible type 'restrict const volatile void*[7]'
+ array element type 'const volatile void*' changed:
+ 'const volatile void*' changed to 'restrict const volatile void*'
+ type name changed from 'const volatile void*[7]' to 'restrict const volatile void*[7]'
type size hasn't changed
type of 'F r_f' changed:
- entity changed from 'typedef F' to compatible type 'restrict const volatile volatile void* const[7]'
- array element type 'const volatile void* const' changed:
- 'const volatile void* const' changed to 'restrict const volatile volatile void* const'
- type name changed from 'const volatile void* const[7]' to 'restrict const volatile volatile void* const[7]'
+ entity changed from 'typedef F' to compatible type 'restrict const volatile void*[7]'
+ array element type 'const volatile void*' changed:
+ 'const volatile void*' changed to 'restrict const volatile void*'
+ type name changed from 'const volatile void*[7]' to 'restrict const volatile void*[7]'
type size hasn't changed