mirror of
git://sourceware.org/git/libabigail.git
synced 2025-03-07 15:17:39 +00:00
Delay non-complete class type resolution up to end of corpus reading
From the DWARF emitted by GCC 4.4.7 for libstdc++ we encountered an
interesting construct.
A non-complete version of std::runtime_error is declared in
libstdc++-v3/src/functexcept.cc and is represented in DWARF as:
[ 37344] class_type
name (strp) "runtime_error"
declaration (flag)
Then a bit later, that *non-complete* class is used as a base class
for a class, *without* being fully defined! This shouldn't happen
but, well, it does:
[ 3b3a1] class_type
specification (ref4) [ 3733e]
byte_size (data1) 16
decl_file (data1) 5
decl_line (data1) 141
containing_type (ref4) [ 3734a]
sibling (ref4) [3b405]
[ 3b3b1] inheritance
type (ref4) [ 37344] <---- here.
The thing is that, later, in another translation unit
(libstdc++-v3/src/stdexcept.cc), that same class is defined fully:
[ 7e9f9] class_type
name (strp) "runtime_error"
declaration (flag)
[...]
[ 80c95] class_type
specification (ref4) [ 7e9f9]
byte_size (data1) 16
decl_file (data1) 4
decl_line (data1) 108
containing_type (ref4) [ 7e9ff]
sibling (ref4) [ 80d2b]
[...] <---------- and the definition goes here.
But then you see that the DIE offset of the "version" of the
runtime_error class that is "defined" libstdc++-v3/src/stdexcept.cc in
is different from the version that is only declared in
libstdc++-v3/src/functexcept.cc. But virtue of the "One Definition
Rule", we can assume that they designate the same type. But still,
runtime_error should have been defined in
libstdc++-v3/src/stdexcept.cc. Anyhow, libabigail needs to be able to
handle this. That is, it needs to wait until the entire ABI corpus is
loaded from DWARF, then lookup the definition of all the non-complete
types we have encountered.
And then only after that non-complete type resolution has taken place,
we can proceed with type canonicalizing, rather than doing it after
the loading of each translation unit like what we were doing
previously.
This is what this patch does.
* include/abg-fwd.h (lookup_type_in_corpus): Declare new function.
* src/abg-corpus.cc (lookup_type_in_corpus): Define new function
here.
* include/abg-ir.h (function_types_type): Declare new typedef.
(translation_unit::get_canonical_function_type): Remove member function.
(translation_unit::bind_function_type_life_time): Declare new
member function.
(classes_type): New typedef.
* src/abg-ir.cc
(translation_unit::priv::canonical_function_types_): Remove data
member.
(translation_unit::priv::function_types): New data member.
(translation_unit::get_canonical_function_type): Remove this
function definition.
(translation_unit::bind_function_type_life_time): New function
definition.
(lookup_node_in_scope): Ensure that the type returned is
complete.
* src/abg-dwarf-reader.cc (string_classes_map): New typedef.
(read_context::decl_only_classes_map_): New data member.
(read_context::declaration_only_classes): New accessor.
(read_context::{maybe_schedule_declaration_only_class_for_resolution,
is_decl_only_class_scheduled_for_resolution,
resolve_declaration_only_classes, current_elf_file_is_executable,
current_elf_file_is_dso}): Define new member functions.
(read_context::clear_per_translation_unit_data): Do not clear the
data structures that associate DIEs to decls/types or that contain
the types to canonicalize here. Rather, clear them ...
(read_context::clear_per_corpus_data): ... here instead.
(read_context::build_translation_unit_and_add_to_ir): Do not
perform late type canonicalizing here. Rather, do it ...
(read_debug_info_into_corpus): ... here instead. And before that,
call read_context::clear_per_corpus_data() and the new
read_context::resolve_declaration_only_classes() here.
(build_class_type_and_add_to_ir): Schedule the non-complete types
for resolution to complete types. Assert that base classes that
are non-complete are scheduled to be completed.
(build_function_decl): Do not try to canonicalize function types
this early, systematically. Now, all the non-complete types needs
to be completed before starting canonicalizing. So let function
types go through the normal processes of deciding when to
canonicalize them. But then, bind the life time of the function
type to the life time of the current translation unit.
(maybe_canonicalize_type): If a class type is non-complete,
schedule it for late canonicalizing.
* src/abg-hash.cc (class_decl:#️⃣:operator()(const class_decl&)
const): During hashing, a base class should be complete.
* src/abg-reader.cc
(read_context::clear_per_translation_unit_data): Do not clear
id/xml node, and type maps here. Rather, clear it ...
(read_context::clear_per_corpus_data): ... here instead.
(read_translation_unit_from_input): Do not perform late
canonicalizing here. Rather, do it ...
(read_corpus_from_input): ... here. Also, call the new
read_context::clear_per_corpus_data() here.
(build_function_decl): Do not canonicalize function types here so
early. Rather, bind the life time of the function type to the
life time of the translation unit.
* src/abg-writer.cc (write_translation_unit): Do not clear the
type/ID map here.
* tests/data/test-read-dwarf/test2.so.abi: Adjust test input.
Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
parent
705a6ae186
commit
635e5fa6b2
@ -464,6 +464,9 @@ void
|
||||
fqn_to_components(const std::string&,
|
||||
std::list<string>&);
|
||||
|
||||
const shared_ptr<decl_base>
|
||||
lookup_type_in_corpus(const string&, const corpus&);
|
||||
|
||||
const shared_ptr<decl_base>
|
||||
lookup_type_in_translation_unit(const string&,
|
||||
const translation_unit&);
|
||||
|
@ -179,6 +179,9 @@ class function_decl;
|
||||
/// Convenience typedef for a shared pointer on a @ref function_type
|
||||
typedef shared_ptr<function_type> function_type_sptr;
|
||||
|
||||
/// Convenience typedef fo a vector of @ref function_type_sptr
|
||||
typedef vector<function_type_sptr> function_types_type;
|
||||
|
||||
/// Convenience typedef for a weak pointer on a @ref function_type
|
||||
typedef weak_ptr<function_type> function_type_wptr;
|
||||
|
||||
@ -258,8 +261,8 @@ public:
|
||||
bool
|
||||
operator==(const translation_unit&) const;
|
||||
|
||||
function_type_sptr
|
||||
get_canonical_function_type(function_type_sptr ftype) const;
|
||||
void
|
||||
bind_function_type_life_time(function_type_sptr) const;
|
||||
|
||||
virtual bool
|
||||
traverse(ir_node_visitor& v);
|
||||
@ -578,6 +581,9 @@ class class_decl;
|
||||
/// Convenience typedef for a shared pointer on a @ref class_decl
|
||||
typedef shared_ptr<class_decl> class_decl_sptr;
|
||||
|
||||
/// Convenience typedef for a vector of @ref class_decl_sptr
|
||||
typedef vector<class_decl_sptr> classes_type;
|
||||
|
||||
/// Convenience typedef for a weak pointer on a @ref class_decl.
|
||||
typedef weak_ptr<class_decl> class_decl_wptr;
|
||||
|
||||
|
@ -1832,5 +1832,28 @@ corpus::get_exported_decls_builder() const
|
||||
return priv_->exported_decls_builder;
|
||||
}
|
||||
|
||||
/// Lookup a type definition in all the translation units of a given
|
||||
/// ABI corpus.
|
||||
///
|
||||
/// @param @param qn the fully qualified name of the type to lookup.
|
||||
///
|
||||
/// @param abi_corpus the ABI corpus which to look the type up in.
|
||||
///
|
||||
/// @return the type definition if any was found, or a NULL pointer.
|
||||
const decl_base_sptr
|
||||
lookup_type_in_corpus(const string& qn, const corpus& abi_corpus)
|
||||
{
|
||||
decl_base_sptr result;
|
||||
|
||||
for (translation_units::const_iterator tu =
|
||||
abi_corpus.get_translation_units().begin();
|
||||
tu != abi_corpus.get_translation_units().end();
|
||||
++tu)
|
||||
if ((result = lookup_type_in_translation_unit(qn, **tu)))
|
||||
break;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}// end namespace ir
|
||||
}// end namespace abigail
|
||||
|
@ -108,6 +108,10 @@ typedef stack<scope_decl*> scope_stack_type;
|
||||
/// value is also a dwarf offset.
|
||||
typedef unordered_map<Dwarf_Off, Dwarf_Off> offset_offset_map;
|
||||
|
||||
/// Convenience typedef for a map which key is a string and which
|
||||
/// value is a vector of smart pointer to a class.
|
||||
typedef unordered_map<string, classes_type> string_classes_map;
|
||||
|
||||
static bool
|
||||
find_symbol_table_section(Elf* elf_handle, Elf_Scn*& section);
|
||||
|
||||
@ -1729,6 +1733,7 @@ class read_context
|
||||
die_class_map_type die_wip_classes_map_;
|
||||
vector<Dwarf_Off> types_to_canonicalize_;
|
||||
vector<Dwarf_Off> alt_types_to_canonicalize_;
|
||||
string_classes_map decl_only_classes_map_;
|
||||
die_tu_map_type die_tu_map_;
|
||||
corpus_sptr cur_corpus_;
|
||||
translation_unit_sptr cur_tu_;
|
||||
@ -1782,6 +1787,17 @@ public:
|
||||
/// entire ABI corpus.
|
||||
void
|
||||
clear_per_translation_unit_data()
|
||||
{
|
||||
while (!scope_stack().empty())
|
||||
scope_stack().pop();
|
||||
var_decls_to_re_add_to_tree().clear();
|
||||
type_decl::get_void_type_decl()->set_scope(0);
|
||||
}
|
||||
|
||||
/// Clear the data that is relevant for the current corpus being
|
||||
/// read.
|
||||
void
|
||||
clear_per_corpus_data()
|
||||
{
|
||||
die_decl_map().clear();
|
||||
alternate_die_decl_map().clear();
|
||||
@ -1789,10 +1805,6 @@ public:
|
||||
die_type_map(/*in_alt_di=*/false).clear();
|
||||
types_to_canonicalize(/*in_alt_di=*/true).clear();
|
||||
types_to_canonicalize(/*in_alt_di=*/false).clear();
|
||||
while (!scope_stack().empty())
|
||||
scope_stack().pop();
|
||||
var_decls_to_re_add_to_tree().clear();
|
||||
type_decl::get_void_type_decl()->set_scope(0);
|
||||
}
|
||||
|
||||
unsigned short
|
||||
@ -2170,6 +2182,118 @@ public:
|
||||
return (i != die_wip_classes_map().end());
|
||||
}
|
||||
|
||||
/// Getter for the map of declaration-only classes that are to be
|
||||
/// resolved to their definition classes by the end of the corpus
|
||||
/// loading.
|
||||
///
|
||||
/// @return a map of string -> vector of classes where the key is
|
||||
/// the fully qualified name of the class and the value is the
|
||||
/// vector of declaration-only class.
|
||||
const string_classes_map&
|
||||
declaration_only_classes() const
|
||||
{return decl_only_classes_map_;}
|
||||
|
||||
/// Getter for the map of declaration-only classes that are to be
|
||||
/// resolved to their definition classes by the end of the corpus
|
||||
/// loading.
|
||||
///
|
||||
/// @return a map of string -> vector of classes where the key is
|
||||
/// the fully qualified name of the class and the value is the
|
||||
/// vector of declaration-only class.
|
||||
string_classes_map&
|
||||
declaration_only_classes()
|
||||
{return decl_only_classes_map_;}
|
||||
|
||||
/// If a given class is a declaration-only class then stash it on
|
||||
/// the side so that at the end of the corpus reading we can resolve
|
||||
/// it to its definition.
|
||||
///
|
||||
/// @param klass the class to consider.
|
||||
void
|
||||
maybe_schedule_declaration_only_class_for_resolution(class_decl_sptr& klass)
|
||||
{
|
||||
if (klass->get_is_declaration_only()
|
||||
&& klass->get_definition_of_declaration() == 0)
|
||||
{
|
||||
string qn = klass->get_qualified_name();
|
||||
string_classes_map::iterator record =
|
||||
declaration_only_classes().find(qn);
|
||||
if (record == declaration_only_classes().end())
|
||||
declaration_only_classes()[qn].push_back(klass);
|
||||
else
|
||||
record->second.push_back(klass);
|
||||
}
|
||||
}
|
||||
|
||||
/// Test if a given declaration-only class has been scheduled for
|
||||
/// resolution to a defined class.
|
||||
///
|
||||
/// @param klass the class to consider for the test.
|
||||
///
|
||||
/// @return true iff @p klass is a declaration-only class and if
|
||||
/// it's been scheduled for resolution to a defined class.
|
||||
bool
|
||||
is_decl_only_class_scheduled_for_resolution(class_decl_sptr& klass)
|
||||
{
|
||||
if (klass->get_is_declaration_only())
|
||||
return (declaration_only_classes().find(klass->get_qualified_name())
|
||||
!= declaration_only_classes().end());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Walk the declaration-only classes that have been found during
|
||||
/// the building of the corpus and resolve them to their definitions.
|
||||
void
|
||||
resolve_declaration_only_classes()
|
||||
{
|
||||
vector<string> resolved_classes;
|
||||
|
||||
for (string_classes_map::iterator i =
|
||||
declaration_only_classes().begin();
|
||||
i != declaration_only_classes().end();
|
||||
++i)
|
||||
{
|
||||
bool to_resolve = false;
|
||||
for (classes_type::iterator j = i->second.begin();
|
||||
j != i->second.end();
|
||||
++j)
|
||||
if ((*j)->get_is_declaration_only()
|
||||
&& ((*j)->get_definition_of_declaration() == 0))
|
||||
to_resolve = true;
|
||||
|
||||
if (!to_resolve)
|
||||
{
|
||||
resolved_classes.push_back(i->first);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (decl_base_sptr type_decl = lookup_type_in_corpus(i->first,
|
||||
*current_corpus()))
|
||||
{
|
||||
class_decl_sptr klass = is_class_type(type_decl);
|
||||
assert(klass);
|
||||
if (klass->get_is_declaration_only())
|
||||
klass = klass->get_definition_of_declaration();
|
||||
assert(!klass->get_is_declaration_only());
|
||||
for (classes_type::iterator j = i->second.begin();
|
||||
j != i->second.end();
|
||||
++j)
|
||||
{
|
||||
if ((*j)->get_is_declaration_only()
|
||||
&& ((*j)->get_definition_of_declaration() == 0))
|
||||
(*j)->set_definition_of_declaration(klass);
|
||||
}
|
||||
resolved_classes.push_back(i->first);
|
||||
}
|
||||
}
|
||||
|
||||
for (vector<string>::iterator i = resolved_classes.begin();
|
||||
i != resolved_classes.end();
|
||||
++i)
|
||||
declaration_only_classes().erase(*i);
|
||||
}
|
||||
|
||||
/// Return a reference to the vector containing the offsets of the
|
||||
/// types that need late canonicalizing.
|
||||
///
|
||||
@ -2896,6 +3020,31 @@ public:
|
||||
elf_architecture() const
|
||||
{return elf_architecture_;}
|
||||
|
||||
/// Test if the current elf file being read is an executable.
|
||||
///
|
||||
/// @return true iff the current elf file being read is an
|
||||
/// executable.
|
||||
bool
|
||||
current_elf_file_is_executable() const
|
||||
{
|
||||
GElf_Ehdr eh_mem;
|
||||
GElf_Ehdr* elf_header = gelf_getehdr(elf_handle(), &eh_mem);
|
||||
return elf_header->e_type == ET_EXEC;
|
||||
}
|
||||
|
||||
/// Test if the current elf file being read is a dynamic shared
|
||||
/// object.
|
||||
///
|
||||
/// @return true iff the current elf file being read is a
|
||||
/// dynamic shared object.
|
||||
bool
|
||||
current_elf_file_is_dso() const
|
||||
{
|
||||
GElf_Ehdr eh_mem;
|
||||
GElf_Ehdr* elf_header = gelf_getehdr(elf_handle(), &eh_mem);
|
||||
return elf_header->e_type == ET_DYN;
|
||||
}
|
||||
|
||||
/// Getter for the map of global variables symbol address -> global
|
||||
/// variable symbol index.
|
||||
///
|
||||
@ -5757,20 +5906,6 @@ build_translation_unit_and_add_to_ir(read_context& ctxt,
|
||||
|
||||
result->set_is_constructed(true);
|
||||
|
||||
/// Now, look at the types that needs to be canonicalized after the
|
||||
/// translation has been constructed (which is just now) and
|
||||
/// canonicalize them.
|
||||
///
|
||||
/// The types need to be constructed at the end of the translation
|
||||
/// unit reading phase because some types are modified by some DIEs
|
||||
/// even after the principal DIE describing the type has been read;
|
||||
/// this happens for clones of virtual destructors (for instance) or
|
||||
/// even for some static data members. We need to that for types
|
||||
/// are in the alternate debug info section and for types that in
|
||||
/// the main debug info section.
|
||||
|
||||
ctxt.perform_late_type_canonicalizing();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -6133,9 +6268,12 @@ build_class_type_and_add_to_ir(read_context& ctxt,
|
||||
ctxt.associate_die_to_type(dwarf_dieoffset(die), is_in_alt_di, result);
|
||||
|
||||
if (!has_child)
|
||||
{
|
||||
// TODO: set the access specifier for the declaration-only class
|
||||
// here.
|
||||
return result;
|
||||
ctxt.maybe_schedule_declaration_only_class_for_resolution(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
ctxt.die_wip_classes_map()[dwarf_dieoffset(die)] = result;
|
||||
|
||||
@ -6191,6 +6329,8 @@ build_class_type_and_add_to_ir(read_context& ctxt,
|
||||
? offset
|
||||
: -1,
|
||||
is_virt));
|
||||
if (b->get_is_declaration_only())
|
||||
assert(ctxt.is_decl_only_class_scheduled_for_resolution(b));
|
||||
result->add_base_specifier(base);
|
||||
}
|
||||
// Handle data members.
|
||||
@ -6292,6 +6432,7 @@ build_class_type_and_add_to_ir(read_context& ctxt,
|
||||
}
|
||||
}
|
||||
|
||||
ctxt.maybe_schedule_declaration_only_class_for_resolution(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -6952,7 +7093,7 @@ build_function_decl(read_context& ctxt,
|
||||
tu->get_address_size(),
|
||||
tu->get_address_size()));
|
||||
|
||||
fn_type = tu->get_canonical_function_type(fn_type);
|
||||
tu->bind_function_type_life_time(fn_type);
|
||||
|
||||
result.reset(is_method
|
||||
? new class_decl::method_decl(fname, fn_type,
|
||||
@ -6998,6 +7139,8 @@ build_function_decl(read_context& ctxt,
|
||||
static corpus_sptr
|
||||
read_debug_info_into_corpus(read_context& ctxt)
|
||||
{
|
||||
ctxt.clear_per_corpus_data();
|
||||
|
||||
if (!ctxt.current_corpus())
|
||||
{
|
||||
corpus_sptr corp (new corpus(ctxt.elf_path()));
|
||||
@ -7042,6 +7185,22 @@ read_debug_info_into_corpus(read_context& ctxt)
|
||||
assert(ir_node);
|
||||
}
|
||||
|
||||
ctxt.resolve_declaration_only_classes();
|
||||
|
||||
/// Now, look at the types that needs to be canonicalized after the
|
||||
/// translation has been constructed (which is just now) and
|
||||
/// canonicalize them.
|
||||
///
|
||||
/// The types need to be constructed at the end of the translation
|
||||
/// unit reading phase because some types are modified by some DIEs
|
||||
/// even after the principal DIE describing the type has been read;
|
||||
/// this happens for clones of virtual destructors (for instance) or
|
||||
/// even for some static data members. We need to that for types
|
||||
/// are in the alternate debug info section and for types that in
|
||||
/// the main debug info section.
|
||||
|
||||
ctxt.perform_late_type_canonicalizing();
|
||||
|
||||
ctxt.current_corpus()->sort_functions();
|
||||
ctxt.current_corpus()->sort_variables();
|
||||
|
||||
@ -7074,7 +7233,13 @@ maybe_canonicalize_type(Dwarf_Off die_offset,
|
||||
type_base_sptr t = ctxt.lookup_type_from_die_offset(die_offset, in_alt_di);
|
||||
assert(t);
|
||||
|
||||
if (!type_has_non_canonicalized_subtype(t))
|
||||
if (class_decl_sptr klass = is_class_type(t))
|
||||
{
|
||||
if (klass->get_is_declaration_only()
|
||||
&& (klass->get_definition_of_declaration() == 0))
|
||||
ctxt.schedule_type_for_late_canonicalization(die_offset, in_alt_di);
|
||||
}
|
||||
else if (!type_has_non_canonicalized_subtype(t))
|
||||
canonicalize(t);
|
||||
else
|
||||
ctxt.schedule_type_for_late_canonicalization(die_offset, in_alt_di);
|
||||
|
@ -616,7 +616,13 @@ class_decl::hash::operator()(const class_decl& t) const
|
||||
t.get_base_specifiers().begin();
|
||||
b != t.get_base_specifiers().end();
|
||||
++b)
|
||||
v = hashing::combine_hashes(v, hash_base(**b));
|
||||
{
|
||||
class_decl_sptr cl = (*b)->get_base_class();
|
||||
assert(cl
|
||||
&& (!cl->get_is_declaration_only()
|
||||
|| cl->get_definition_of_declaration()));
|
||||
v = hashing::combine_hashes(v, hash_base(**b));
|
||||
}
|
||||
|
||||
// Hash member types.
|
||||
#if 0
|
||||
|
@ -164,7 +164,7 @@ struct translation_unit::priv
|
||||
std::string path_;
|
||||
location_manager loc_mgr_;
|
||||
mutable global_scope_sptr global_scope_;
|
||||
mutable fn_type_ptr_map canonical_function_types_;
|
||||
mutable function_types_type function_types_;
|
||||
|
||||
priv()
|
||||
: is_constructed_(),
|
||||
@ -301,32 +301,16 @@ translation_unit::operator==(const translation_unit& other)const
|
||||
return *get_global_scope() == *other.get_global_scope();
|
||||
}
|
||||
|
||||
/// Return the canonical version of a given instance of @ref function_type.
|
||||
/// Ensure that the life time of a function type is bound to the life
|
||||
/// time of the current translation unit.
|
||||
///
|
||||
/// A given translation units keeps only one copy of each function
|
||||
/// type that is used in the unit. So each function type that is
|
||||
/// built somewhere needs to be passed to this function to
|
||||
/// canonicalize it and/or return the canonical version.
|
||||
///
|
||||
/// Note that it really is the translation unit that 'owns' the
|
||||
/// function types that are live in the translation unit. This is
|
||||
/// unlike the other kinds of types that are owned by the scope where
|
||||
/// they are defined.
|
||||
///
|
||||
/// @param ftype the function type to canonicalize.
|
||||
///
|
||||
/// @return the resulting canonical type.
|
||||
function_type_sptr
|
||||
translation_unit::get_canonical_function_type(function_type_sptr ftype) const
|
||||
{
|
||||
fn_type_ptr_map::iterator i = priv_->canonical_function_types_.find(ftype);
|
||||
if (i == priv_->canonical_function_types_.end())
|
||||
{
|
||||
priv_->canonical_function_types_[ftype] = true;
|
||||
return ftype;
|
||||
}
|
||||
return dynamic_pointer_cast<function_type>(i->first);
|
||||
}
|
||||
/// @param ftype the function time which life time to bind to the life
|
||||
/// time of the current instance of @ref translation_unit. That is,
|
||||
/// it's onlyh when the translation unit is destroyed that the
|
||||
/// function type can be destroyed to.
|
||||
void
|
||||
translation_unit::bind_function_type_life_time(function_type_sptr ftype) const
|
||||
{priv_->function_types_.push_back(ftype);}
|
||||
|
||||
/// This implements the ir_traversable_base::traverse virtual
|
||||
/// function.
|
||||
@ -3698,6 +3682,10 @@ lookup_node_in_scope(const list<string>& fqn,
|
||||
node = dynamic_pointer_cast<NodeKind>(*m);
|
||||
if (node && get_node_name(node) == *c)
|
||||
{
|
||||
if (class_decl_sptr cl =
|
||||
dynamic_pointer_cast<class_decl>(node))
|
||||
if (cl->get_is_declaration_only())
|
||||
continue;
|
||||
resulting_decl = convert_node_to_decl(node);
|
||||
break;
|
||||
}
|
||||
|
@ -586,11 +586,17 @@ public:
|
||||
void
|
||||
clear_per_translation_unit_data()
|
||||
{
|
||||
clear_id_xml_node_map();
|
||||
clear_type_map();
|
||||
clear_id_xml_node_map();
|
||||
clear_xml_node_decl_map();
|
||||
clear_decls_stack();
|
||||
}
|
||||
|
||||
/// Clear all the data that must absolutely be cleared at the end of
|
||||
/// the parsing of an ABI corpus.
|
||||
void
|
||||
clear_per_corpus_data()
|
||||
{
|
||||
clear_id_xml_node_map();
|
||||
clear_type_map();
|
||||
clear_types_to_canonicalize();
|
||||
}
|
||||
|
||||
@ -962,8 +968,6 @@ read_translation_unit_from_input(read_context& ctxt,
|
||||
|
||||
xmlTextReaderNext(reader.get());
|
||||
|
||||
ctxt.perform_late_type_canonicalizing();
|
||||
|
||||
ctxt.clear_per_translation_unit_data();
|
||||
|
||||
return true;
|
||||
@ -1135,6 +1139,8 @@ read_corpus_from_input(read_context& ctxt)
|
||||
ctxt.set_corpus(c);
|
||||
}
|
||||
|
||||
ctxt.clear_per_corpus_data();
|
||||
|
||||
corpus& corp = *ctxt.get_corpus();
|
||||
|
||||
xml::xml_char_sptr path_str = XML_READER_GET_ATTRIBUTE(reader, "path");
|
||||
@ -1197,6 +1203,7 @@ read_corpus_from_input(read_context& ctxt)
|
||||
}
|
||||
while (is_ok);
|
||||
|
||||
ctxt.perform_late_type_canonicalizing();
|
||||
corp.set_origin(corpus::NATIVE_XML_ORIGIN);
|
||||
|
||||
return ctxt.get_corpus();;
|
||||
@ -2075,7 +2082,7 @@ build_function_decl(read_context& ctxt,
|
||||
if (fn_decl->get_symbol() && fn_decl->get_symbol()->is_public())
|
||||
fn_decl->set_is_in_public_symbol_table(true);
|
||||
|
||||
fn_type = ctxt.get_translation_unit()->get_canonical_function_type(fn_type);
|
||||
ctxt.get_translation_unit()->bind_function_type_life_time(fn_type);
|
||||
|
||||
fn_decl->set_type(fn_type);
|
||||
ctxt.maybe_canonicalize_type(fn_type);
|
||||
|
@ -859,8 +859,6 @@ write_translation_unit(const translation_unit& tu,
|
||||
ostream& o = ctxt.get_ostream();
|
||||
const config& c = ctxt.get_config();
|
||||
|
||||
ctxt.clear_type_id_map();
|
||||
|
||||
do_indent(o, indent);
|
||||
|
||||
o << "<abi-instr version='"
|
||||
|
@ -48,30 +48,26 @@
|
||||
<abi-instr version='1.0' address-size='64' path='test2-1.cc'>
|
||||
<class-decl name='second_type' size-in-bits='64' is-struct='yes' visibility='default' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test2.h' line='12' column='1' id='type-id-7'>
|
||||
<data-member access='public' layout-offset-in-bits='0'>
|
||||
<var-decl name='member0' type-id='type-id-8' visibility='default' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test2.h' line='14' column='1'/>
|
||||
<var-decl name='member0' type-id='type-id-2' visibility='default' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test2.h' line='14' column='1'/>
|
||||
</data-member>
|
||||
<data-member access='public' layout-offset-in-bits='32'>
|
||||
<var-decl name='member1' type-id='type-id-9' visibility='default' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test2.h' line='15' column='1'/>
|
||||
<var-decl name='member1' type-id='type-id-3' visibility='default' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test2.h' line='15' column='1'/>
|
||||
</data-member>
|
||||
<member-function access='public' constructor='yes'>
|
||||
<function-decl name='second_type' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test2.h' line='17' column='1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='64'>
|
||||
<parameter type-id='type-id-10' is-artificial='yes'/>
|
||||
<parameter type-id='type-id-8' is-artificial='yes'/>
|
||||
</function-decl>
|
||||
</member-function>
|
||||
<member-function access='public' constructor='yes'>
|
||||
<function-decl name='second_type' mangled-name='_ZN11second_typeC1Ev' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test2.h' line='17' column='1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='64' elf-symbol-id='_ZN11second_typeC1Ev'>
|
||||
<parameter type-id='type-id-10' is-artificial='yes'/>
|
||||
<parameter type-id='type-id-8' is-artificial='yes'/>
|
||||
</function-decl>
|
||||
</member-function>
|
||||
</class-decl>
|
||||
<type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-11'/>
|
||||
<typedef-decl name='integer' type-id='type-id-11' id='type-id-8'/>
|
||||
<type-decl name='unsigned char' size-in-bits='8' alignment-in-bits='8' id='type-id-12'/>
|
||||
<typedef-decl name='character' type-id='type-id-12' id='type-id-9'/>
|
||||
<pointer-type-def type-id='type-id-7' size-in-bits='64' alignment-in-bits='64' id='type-id-10'/>
|
||||
<pointer-type-def type-id='type-id-7' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
|
||||
<namespace-decl name='a'>
|
||||
<function-decl name='build_second_type' mangled-name='_ZN1a17build_second_typeEv' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test2-1.cc' line='13' column='1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='64' elf-symbol-id='_ZN1a17build_second_typeEv'>
|
||||
<return type-id='type-id-10'/>
|
||||
<return type-id='type-id-8'/>
|
||||
</function-decl>
|
||||
</namespace-decl>
|
||||
</abi-instr>
|
||||
|
Loading…
Reference in New Issue
Block a user