Bug 27236 - Don't forget to emit some referenced types

Since we arranged to only emit referenced types in translation units
where they belong, it appears that in some cases we forget to emit
some referenced types.

This is because some referenced types might belong to a translation
unit that is *already* emitted by the time we detect that a type is
referenced.

To fix this correctly, we should probably have a pass that walks the
corpus to detect referenced types, so that we have their set even
before we start emitting translation units.

But for now, the patch just detects when we are emitting the last
translation unit.  In that case all the non-emitted referenced types
are emitted.  It doesn't seem to be an issue if those don't belong to
that translation unit, compared to their original (from the DWARF)
type.

	* include/abg-writer.h (write_translation_unit): Add a new
	parameter that says if we are emitting the last TU.
	* src/abg-writer.cc (write_translation_unit::{type_is_emitted,
	decl_only_type_is_emitted}): Constify these methods.
	(write_context::has_non_emitted_referenced_types): Define new
	member function using the const methods above.
	(write_translation_unit): When emitting the last TU, emit all the
	referenced types.
	(write_corpus): Set signal when emitting the last translation
	unit.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
Dodji Seketeli 2021-07-29 17:12:38 +02:00
parent cc2574121f
commit dd0861c9a8
2 changed files with 79 additions and 27 deletions

View File

@ -100,7 +100,8 @@ set_ostream(write_context& ctxt, ostream& os);
bool
write_translation_unit(write_context& ctxt,
const translation_unit& tu,
const unsigned indent);
const unsigned indent,
bool last = true);
bool
write_corpus_to_archive(const corpus& corp,

View File

@ -505,6 +505,30 @@ public:
get_referenced_non_canonical_types() const
{return m_referenced_non_canonical_types_set;}
/// Test if there are non emitted referenced types.
///
/// @return true iff there are non emitted referenced types.
bool
has_non_emitted_referenced_types() const
{
for (const auto t : get_referenced_types())
if (!type_is_emitted(t)
&& !decl_only_type_is_emitted(t))
return false;
for (const auto t : get_referenced_non_canonical_types())
if (!type_is_emitted(t)
&& !decl_only_type_is_emitted(t))
return false;
for (const auto t : get_referenced_non_canonical_types())
if (!type_is_emitted(t)
&& !decl_only_type_is_emitted(t))
return false;
return true;
}
/// Record a given type as being referenced by a pointer, a
/// reference or a typedef type that is being emitted to the XML
/// output.
@ -708,7 +732,7 @@ public:
/// @return true if the type has already been emitted, false
/// otherwise.
bool
type_is_emitted(const type_base *t)
type_is_emitted(const type_base *t) const
{
return m_emitted_type_set.find(t) != m_emitted_type_set.end();
}
@ -720,7 +744,7 @@ public:
/// @return true if the type has already been emitted, false
/// otherwise.
bool
type_is_emitted(const type_base_sptr& t)
type_is_emitted(const type_base_sptr& t) const
{return type_is_emitted(t.get());}
/// Test if the name of a given decl has been written out to the XML
@ -783,7 +807,7 @@ public:
/// @return true iff the declaration-only class @p t has been
/// emitted.
bool
decl_only_type_is_emitted(const type_base* t)
decl_only_type_is_emitted(const type_base* t) const
{
type_ptr_set_type::const_iterator i = m_emitted_decl_only_set.find(t);
if (i == m_emitted_decl_only_set.end())
@ -798,7 +822,7 @@ public:
/// @return true iff the declaration-only class @p t has been
/// emitted.
bool
decl_only_type_is_emitted(const type_base_sptr& t)
decl_only_type_is_emitted(const type_base_sptr& t) const
{return decl_only_type_is_emitted(t.get());}
/// Record a declaration as emitted in the abixml output.
@ -2228,12 +2252,31 @@ write_canonical_types_of_scope(const scope_decl &scope,
/// @param indent how many indentation spaces to use during the
/// serialization.
///
/// @param is_last If true, it means the TU to emit is the last one of
/// the corpus. If this is the case, all the remaining referenced
/// types that were not emitted are going to be emitted here,
/// irrespective of if they belong to this TU or not. This is quite a
/// hack. Ideally, we should have a pass that walks all the TUs,
/// detect their non-emitted referenced types, before hand. Then,
/// when we start emitting the TUs, we know for each TU which
/// non-emitted referenced type should be emitted. As we don't yet
/// have such a pass, we do our best for now.
///
/// @return true upon successful completion, false otherwise.
bool
write_translation_unit(write_context& ctxt,
const translation_unit& tu,
const unsigned indent)
write_translation_unit(write_context& ctxt,
const translation_unit& tu,
const unsigned indent,
bool is_last)
{
if (tu.is_empty() && !is_last)
return false;
if (is_last
&& tu.is_empty()
&& ctxt.has_non_emitted_referenced_types())
return false;
ostream& o = ctxt.get_ostream();
const config& c = ctxt.get_config();
@ -2259,7 +2302,7 @@ write_translation_unit(write_context& ctxt,
<< translation_unit_language_to_string(tu.get_language())
<<"'";
if (tu.is_empty())
if (tu.is_empty() && !is_last)
{
o << "/>\n";
return true;
@ -2304,18 +2347,20 @@ write_translation_unit(write_context& ctxt,
// So this map of type -> string is to contain the referenced types
// we need to emit.
type_ptr_set_type referenced_types_to_emit;
for (type_ptr_set_type::const_iterator i =
ctxt.get_referenced_types().begin();
i != ctxt.get_referenced_types().end();
++i)
if (!ctxt.type_is_emitted(*i)
&& !ctxt.decl_only_type_is_emitted(*i)
// Ensure that the referenced type is emitted in the
// translation that it belongs to.
&& ((*i)->get_translation_unit()->get_absolute_path()
== tu.get_absolute_path()))
{
if (!ctxt.type_is_emitted(*i)
&& !ctxt.decl_only_type_is_emitted(*i)
// Ensure that the referenced type is emitted in the
// translation that it belongs to.
&& (is_last
|| ((*i)->get_translation_unit()->get_absolute_path()
== tu.get_absolute_path())))
referenced_types_to_emit.insert(*i);
}
for (fn_type_ptr_set_type::const_iterator i =
ctxt.get_referenced_function_types().begin();
@ -2325,8 +2370,9 @@ write_translation_unit(write_context& ctxt,
&& !ctxt.decl_only_type_is_emitted(*i)
// Ensure that the referenced type is emitted in the
// translation that it belongs to.
&& ((*i)->get_translation_unit()->get_absolute_path()
== tu.get_absolute_path()))
&& (is_last
|| ((*i)->get_translation_unit()->get_absolute_path()
== tu.get_absolute_path())))
// A referenced type that was not emitted at all must be
// emitted now.
referenced_types_to_emit.insert(*i);
@ -2339,8 +2385,9 @@ write_translation_unit(write_context& ctxt,
&& !ctxt.decl_only_type_is_emitted(*i)
// Ensure that the referenced type is emitted in the
// translation that it belongs to.
&& ((*i)->get_translation_unit()->get_absolute_path()
== tu.get_absolute_path()))
&& (is_last
|| ((*i)->get_translation_unit()->get_absolute_path()
== tu.get_absolute_path())))
// A referenced type that was not emitted at all must be
// emitted now.
referenced_types_to_emit.insert(*i);
@ -2399,8 +2446,9 @@ write_translation_unit(write_context& ctxt,
&& !ctxt.decl_only_type_is_emitted(*i)
// Ensure that the referenced type is emitted in the
// translation that it belongs to.
&& ((*i)->get_translation_unit()->get_absolute_path()
== tu.get_absolute_path()))
&& (is_last
|| ((*i)->get_translation_unit()->get_absolute_path()
== tu.get_absolute_path())))
// A referenced type that was not emitted at all must be
// emitted now.
referenced_types_to_emit.insert(*i);
@ -2413,8 +2461,9 @@ write_translation_unit(write_context& ctxt,
&& !ctxt.decl_only_type_is_emitted(*i)
// Ensure that the referenced type is emitted in the
// translation that it belongs to.
&& ((*i)->get_translation_unit()->get_absolute_path()
== tu.get_absolute_path()))
&& (is_last
|| ((*i)->get_translation_unit()->get_absolute_path()
== tu.get_absolute_path())))
// A referenced type that was not emitted at all must be
// emitted now.
referenced_types_to_emit.insert(*i);
@ -4453,14 +4502,16 @@ write_corpus(write_context& ctxt,
}
// Now write the translation units.
unsigned nb_tus = corpus->get_translation_units().size(), n = 0;
for (translation_units::const_iterator i =
corpus->get_translation_units().begin();
i != corpus->get_translation_units().end();
++i)
++i, ++n)
{
translation_unit& tu = **i;
if (!tu.is_empty())
write_translation_unit(ctxt, tu, get_indent_to_level(ctxt, indent, 1));
write_translation_unit(ctxt, tu,
get_indent_to_level(ctxt, indent, 1),
n == nb_tus - 1);
}
do_indent_to_level(ctxt, indent, 0);