[applied] writer: Don't forget to emit types referenced by function types

Message ID 871r4id86z.fsf@redhat.com
State New
Headers
Series [applied] writer: Don't forget to emit types referenced by function types |

Commit Message

Dodji Seketeli Oct. 18, 2021, 8:54 a.m. UTC
  Hello,

While looking into something else, I noticed that sometimes the writer
would forget to emit types referenced by function types.  Fixed thus.

	* src/abg-writer.cc (write_referenced_types): Factorize out of ...
	(write_translation_unit): ... here.  Also, use it to write the
	types referenced by emitted function types.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
Applied to master.
---
 src/abg-writer.cc | 199 ++++++++++++++++++++++++++--------------------
 1 file changed, 112 insertions(+), 87 deletions(-)
  

Patch

diff --git a/src/abg-writer.cc b/src/abg-writer.cc
index efc01fa7..3848df77 100644
--- a/src/abg-writer.cc
+++ b/src/abg-writer.cc
@@ -2286,103 +2286,24 @@  referenced_type_should_be_emitted(const type_base *t,
   return false;
 }
 
-/// Serialize a translation unit to an output stream.
+/// Emit the types that were referenced by other emitted types.
 ///
-/// @param ctxt the context of the serialization.  It contains e.g,
-/// the output stream to serialize to.
+/// This is a sub-routine of write_translation_unit.
 ///
-/// @param tu the translation unit to serialize.
+/// @param ctxt the write context to use.
 ///
-/// @param indent how many indentation spaces to use during the
-/// serialization.
+/// @param tu the current translation unit that is being emitted.
 ///
-/// @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.
+/// @param indent the indentation string.
 ///
-/// @return true upon successful completion, false otherwise.
-bool
-write_translation_unit(write_context&		ctxt,
+/// @param is_last whether @p tu is the last translation unit or not.
+static void
+write_referenced_types(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();
-
-  do_indent(o, indent);
-
-  o << "<abi-instr";
-
-  if (tu.get_address_size() != 0)
-    o << " address-size='" << static_cast<int>(tu.get_address_size()) << "'";
-
-  std::string tu_path = tu.get_path();
-  if (ctxt.get_short_locs())
-    tools_utils::base_name(tu_path, tu_path);
-  if (!tu_path.empty())
-    o << " path='" << xml::escape_xml_string(tu_path) << "'";
-
-  if (!tu.get_compilation_dir_path().empty() && ctxt.get_write_comp_dir())
-    o << " comp-dir-path='"
-      << xml::escape_xml_string(tu.get_compilation_dir_path()) << "'";
-
-  if (tu.get_language() != translation_unit::LANG_UNKNOWN)
-    o << " language='"
-      << translation_unit_language_to_string(tu.get_language())
-      <<"'";
-
-  if (tu.is_empty() && !is_last)
-    {
-      o << "/>\n";
-      return true;
-    }
-
-  o << ">\n";
-
-  write_canonical_types_of_scope(*tu.get_global_scope(),
-				 ctxt, indent + c.get_xml_element_indent());
-
-  typedef scope_decl::declarations declarations;
-  typedef declarations::const_iterator const_iterator;
-  const declarations& d = tu.get_global_scope()->get_sorted_member_decls();
-
-  for (const_iterator i = d.begin(); i != d.end(); ++i)
-    {
-      if (type_base_sptr t = is_type(*i))
-	{
-	  // Emit declaration-only classes that are needed. Some of
-	  // these classes can be empty.  Those beasts can be classes
-	  // that only contain member types.  They can also be classes
-	  // considered "opaque".
-	  if (class_decl_sptr class_type = is_class_type(t))
-	    if (class_type->get_is_declaration_only()
-		&& !ctxt.type_is_emitted(class_type))
-	      write_type(class_type, ctxt,
-			 indent + c.get_xml_element_indent());
-	  continue;
-	}
-
-      if (decl_base_sptr d = is_decl(*i))
-	if (ctxt.decl_is_emitted(d))
-	  continue;
-      write_decl(*i, ctxt, indent + c.get_xml_element_indent());
-    }
-
   // Now let's handle types that were referenced, but not yet
   // emitted because they are either:
   //   1/ Types without canonical type
@@ -2479,6 +2400,106 @@  write_translation_unit(write_context&		ctxt,
 	if (referenced_type_should_be_emitted(*i, ctxt, tu, is_last))
 	  referenced_types_to_emit.insert(*i);
     }
+}
+
+/// Serialize a translation unit to an output stream.
+///
+/// @param ctxt the context of the serialization.  It contains e.g,
+/// the output stream to serialize to.
+///
+/// @param tu the translation unit to serialize.
+///
+/// @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,
+		       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();
+
+  do_indent(o, indent);
+
+  o << "<abi-instr";
+
+  if (tu.get_address_size() != 0)
+    o << " address-size='" << static_cast<int>(tu.get_address_size()) << "'";
+
+  std::string tu_path = tu.get_path();
+  if (ctxt.get_short_locs())
+    tools_utils::base_name(tu_path, tu_path);
+  if (!tu_path.empty())
+    o << " path='" << xml::escape_xml_string(tu_path) << "'";
+
+  if (!tu.get_compilation_dir_path().empty() && ctxt.get_write_comp_dir())
+    o << " comp-dir-path='"
+      << xml::escape_xml_string(tu.get_compilation_dir_path()) << "'";
+
+  if (tu.get_language() != translation_unit::LANG_UNKNOWN)
+    o << " language='"
+      << translation_unit_language_to_string(tu.get_language())
+      <<"'";
+
+  if (tu.is_empty() && !is_last)
+    {
+      o << "/>\n";
+      return true;
+    }
+
+  o << ">\n";
+
+  write_canonical_types_of_scope(*tu.get_global_scope(),
+				 ctxt, indent + c.get_xml_element_indent());
+
+  typedef scope_decl::declarations declarations;
+  typedef declarations::const_iterator const_iterator;
+  const declarations& d = tu.get_global_scope()->get_sorted_member_decls();
+
+  for (const_iterator i = d.begin(); i != d.end(); ++i)
+    {
+      if (type_base_sptr t = is_type(*i))
+	{
+	  // Emit declaration-only classes that are needed. Some of
+	  // these classes can be empty.  Those beasts can be classes
+	  // that only contain member types.  They can also be classes
+	  // considered "opaque".
+	  if (class_decl_sptr class_type = is_class_type(t))
+	    if (class_type->get_is_declaration_only()
+		&& !ctxt.type_is_emitted(class_type))
+	      write_type(class_type, ctxt,
+			 indent + c.get_xml_element_indent());
+	  continue;
+	}
+
+      if (decl_base_sptr d = is_decl(*i))
+	if (ctxt.decl_is_emitted(d))
+	  continue;
+      write_decl(*i, ctxt, indent + c.get_xml_element_indent());
+    }
+
+  write_referenced_types(ctxt, tu, indent, is_last);
 
   // Now handle all function types that were not only referenced by
   // emitted types.
@@ -2502,6 +2523,10 @@  write_translation_unit(write_context&		ctxt,
       write_function_type(fn_type, ctxt, indent + c.get_xml_element_indent());
     }
 
+  // After we've written out the live function types, we need to write
+  // the types they referenced.
+  write_referenced_types(ctxt, tu, indent, is_last);
+
   do_indent(o, indent);
   o << "</abi-instr>\n";