compiler: clean up unresolved placeholders for pointer types
Add a new helper routine Type::finish_pointer_types that walks through
the pointer type cache and looks for placeholder types that may have
been created at some point before conversion of named types, and
invokes Type::finish_backend() on said placeholders. This is needed
to handle cases where the compiler manufactures a pointer type as part
of lowering, then a placeholder is created for it due to a call to
Type::backend_type_size(), but there is no explicit reference to the
type in user code.
Change-Id: I9f92f206ed9c341373adcd0f126f3439e9390ccf
Reviewed-on: https://go-review.googlesource.com/51131
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/go/gogo.cc b/go/gogo.cc
index a9d72ff..ca4b454 100644
--- a/go/gogo.cc
+++ b/go/gogo.cc
@@ -4824,6 +4824,8 @@
Runtime::convert_types(this);
this->named_types_are_converted_ = true;
+
+ Type::finish_pointer_types(this);
}
// Convert all names types in a set of bindings.
diff --git a/go/types.cc b/go/types.cc
index ca5f512..91d6091 100644
--- a/go/types.cc
+++ b/go/types.cc
@@ -5516,14 +5516,17 @@
return Type::make_pointer_type(to);
}
+// Cache of pointer types. Key is "to" type, value is pointer type
+// that points to key.
+
+Type::Pointer_type_table Type::pointer_types;
+
// Make a pointer type.
Pointer_type*
Type::make_pointer_type(Type* to_type)
{
- typedef Unordered_map(Type*, Pointer_type*) Hashtable;
- static Hashtable pointer_types;
- Hashtable::const_iterator p = pointer_types.find(to_type);
+ Pointer_type_table::const_iterator p = pointer_types.find(to_type);
if (p != pointer_types.end())
return p->second;
Pointer_type* ret = new Pointer_type(to_type);
@@ -5531,6 +5534,37 @@
return ret;
}
+// This helper is invoked immediately after named types have been
+// converted, to clean up any unresolved pointer types remaining in
+// the pointer type cache.
+//
+// The motivation for this routine: occasionally the compiler creates
+// some specific pointer type as part of a lowering operation (ex:
+// pointer-to-void), then Type::backend_type_size() is invoked on the
+// type (which creates a Btype placeholder for it), that placeholder
+// passed somewhere along the line to the back end, but since there is
+// no reference to the type in user code, there is never a call to
+// Type::finish_backend for the type (hence the Btype remains as an
+// unresolved placeholder). Calling this routine will clean up such
+// instances.
+
+void
+Type::finish_pointer_types(Gogo* gogo)
+{
+ for (Pointer_type_table::const_iterator i = pointer_types.begin();
+ i != pointer_types.end();
+ ++i)
+ {
+ Pointer_type* pt = i->second;
+ Type_btypes::iterator tbti = Type::type_btypes.find(pt);
+ if (tbti != Type::type_btypes.end() && tbti->second.is_placeholder)
+ {
+ pt->finish_backend(gogo, tbti->second.btype);
+ tbti->second.is_placeholder = false;
+ }
+ }
+}
+
// The nil type. We use a special type for nil because it is not the
// same as any other type. In C term nil has type void*, but there is
// no such type in Go.
diff --git a/go/types.h b/go/types.h
index aeb04d6..f659f38 100644
--- a/go/types.h
+++ b/go/types.h
@@ -504,6 +504,9 @@
static Pointer_type*
make_pointer_type(Type*);
+ static void
+ finish_pointer_types(Gogo* gogo);
+
static Type*
make_nil_type();
@@ -1341,6 +1344,12 @@
static Type_functions type_functions_table;
+ // Cache for reusing existing pointer types; maps from pointed-to-type
+ // to pointer type.
+ typedef Unordered_map(Type*, Pointer_type*) Pointer_type_table;
+
+ static Pointer_type_table pointer_types;
+
// The type classification.
Type_classification classification_;
// The backend representation of the type, once it has been