Use backend interface for type descriptors.
authorIan Lance Taylor <iant@google.com>
Sat, 11 Jun 2011 05:16:20 +0000 (05:16 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Sat, 11 Jun 2011 05:16:20 +0000 (05:16 +0000)
* go-gcc.cc: Include "toplev.h".
(Gcc_backend::immutable_struct): New function.
(Gcc_backend::immutable_struct_set_init): New function.
(Gcc_backend::immutable_struct_reference): New function.
* Make-lang.in (go/go-gcc.o): Depend on toplev.h.

From-SVN: r174941

gcc/go/ChangeLog
gcc/go/Make-lang.in
gcc/go/go-gcc.cc
gcc/go/gofrontend/backend.h
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/gogo-tree.cc
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h
gcc/go/gofrontend/types.cc
gcc/go/gofrontend/types.h

index aac428bfa8b5b9fcf1a9b8d5111a2963eccdf2b2..11abbbcd42130b1997f8ec735d7a491410ddaa5a 100644 (file)
@@ -1,3 +1,11 @@
+2011-06-10  Ian Lance Taylor  <iant@google.com>
+
+       * go-gcc.cc: Include "toplev.h".
+       (Gcc_backend::immutable_struct): New function.
+       (Gcc_backend::immutable_struct_set_init): New function.
+       (Gcc_backend::immutable_struct_reference): New function.
+       * Make-lang.in (go/go-gcc.o): Depend on toplev.h.
+
 2011-06-09  Ian Lance Taylor  <iant@google.com>
 
        * go-gcc.cc (Gcc_backend::zero_expression): New function.
index ef5dc753d0a1ca215438e30466250055c5c49482..61a0f3c875a2954eff8ec8e8593609860c47e5ec 100644 (file)
@@ -239,7 +239,8 @@ go/go-lang.o: go/go-lang.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(OPTS_H) \
 GOINCLUDES = -I $(srcdir)/go -I $(srcdir)/go/gofrontend
 
 go/go-gcc.o: go/go-gcc.cc $(GO_SYSTEM_H) $(TREE_H) tree-iterator.h \
-               $(GIMPLE_H) $(GO_C_H) $(GO_GOGO_H) go/gofrontend/backend.h
+               $(GIMPLE_H) toplev.h $(GO_C_H) $(GO_GOGO_H) \
+               go/gofrontend/backend.h
        $(CXX) -c $(GOINCLUDES) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) $< $(OUTPUT_OPTION)
 
 go/%.o: go/gofrontend/%.cc
index 1299e9b53be29b61b08d3207dd8e3e14d4ea54a4..dbdf95f2e7bdabdfb4a9324c4ded2aaf772e9efc 100644 (file)
@@ -32,6 +32,7 @@ extern "C"
 #include "tree.h"
 #include "tree-iterator.h"
 #include "gimple.h"
+#include "toplev.h"
 
 #ifndef ENABLE_BUILD_WITH_CXX
 }
@@ -276,6 +277,16 @@ class Gcc_backend : public Backend
   temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression*, bool,
                     source_location, Bstatement**);
 
+  Bvariable*
+  immutable_struct(const std::string&, bool, Btype*, source_location);
+
+  void
+  immutable_struct_set_init(Bvariable*, const std::string&, bool, Btype*,
+                           source_location, Bexpression*);
+
+  Bvariable*
+  immutable_struct_reference(const std::string&, Btype*, source_location);
+
   // Labels.
 
   Blabel*
@@ -1198,6 +1209,83 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock,
   return new Bvariable(var);
 }
 
+// Create a named immutable initialized data structure.
+
+Bvariable*
+Gcc_backend::immutable_struct(const std::string& name, bool, Btype* btype,
+                             source_location location)
+{
+  tree type_tree = btype->get_tree();
+  if (type_tree == error_mark_node)
+    return this->error_variable();
+  gcc_assert(TREE_CODE(type_tree) == RECORD_TYPE);
+  tree decl = build_decl(location, VAR_DECL,
+                        get_identifier_from_string(name),
+                        build_qualified_type(type_tree, TYPE_QUAL_CONST));
+  TREE_STATIC(decl) = 1;
+  TREE_READONLY(decl) = 1;
+  TREE_CONSTANT(decl) = 1;
+  TREE_USED(decl) = 1;
+  DECL_ARTIFICIAL(decl) = 1;
+
+  // We don't call rest_of_decl_compilation until we have the
+  // initializer.
+
+  go_preserve_from_gc(decl);
+  return new Bvariable(decl);
+}
+
+// Set the initializer for a variable created by immutable_struct.
+// This is where we finish compiling the variable.
+
+void
+Gcc_backend::immutable_struct_set_init(Bvariable* var, const std::string&,
+                                      bool is_common, Btype*,
+                                      source_location,
+                                      Bexpression* initializer)
+{
+  tree decl = var->get_tree();
+  tree init_tree = initializer->get_tree();
+  if (decl == error_mark_node || init_tree == error_mark_node)
+    return;
+
+  DECL_INITIAL(decl) = init_tree;
+
+  // We can't call make_decl_one_only until we set DECL_INITIAL.
+  if (!is_common)
+    TREE_PUBLIC(decl) = 1;
+  else
+    {
+      make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl));
+      resolve_unique_section(decl, 1, 0);
+    }
+
+  rest_of_decl_compilation(decl, 1, 0);
+}
+
+// Return a reference to an immutable initialized data structure
+// defined in another package.
+
+Bvariable*
+Gcc_backend::immutable_struct_reference(const std::string& name, Btype* btype,
+                                       source_location location)
+{
+  tree type_tree = btype->get_tree();
+  if (type_tree == error_mark_node)
+    return this->error_variable();
+  gcc_assert(TREE_CODE(type_tree) == RECORD_TYPE);
+  tree decl = build_decl(location, VAR_DECL,
+                        get_identifier_from_string(name),
+                        build_qualified_type(type_tree, TYPE_QUAL_CONST));
+  TREE_READONLY(decl) = 1;
+  TREE_CONSTANT(decl) = 1;
+  DECL_ARTIFICIAL(decl) = 1;
+  TREE_PUBLIC(decl) = 1;
+  DECL_EXTERNAL(decl) = 1;
+  go_preserve_from_gc(decl);
+  return new Bvariable(decl);
+}
+
 // Make a label.
 
 Blabel*
index 5ece2e698fb024acde7c91ba0a8615353f0d45c7..b18c18c763facacbb730697237274f4408bf1af3 100644 (file)
@@ -361,6 +361,52 @@ class Backend
                     bool address_is_taken, source_location location,
                     Bstatement** pstatement) = 0;
 
+  // Create a named immutable initialized data structure.  This is
+  // used for type descriptors and map descriptors.  This returns a
+  // Bvariable because it corresponds to an initialized const global
+  // variable in C.
+  //
+  // NAME is the name to use for the initialized global variable which
+  // this call will create.
+  //
+  // IS_COMMON is true if NAME may be defined by several packages, and
+  // the linker should merge all such definitions.  If IS_COMMON is
+  // false, NAME should be defined in only one file.  In general
+  // IS_COMMON will be true for the type descriptor of an unnamed type
+  // or a builtin type.
+  //
+  // TYPE will be a struct type; the type of the returned expression
+  // must be a pointer to this struct type.
+  // 
+  // We must create the named structure before we know its
+  // initializer, because the initializer refer to its own address.
+  // After calling this the frontend will call
+  // set_immutable_struct_initializer.
+  virtual Bvariable*
+  immutable_struct(const std::string& name, bool is_common, Btype* type,
+                  source_location) = 0;
+
+  // Set the initial value of a variable created by immutable_struct.
+  // The NAME, IS_COMMON, TYPE, and location parameters are the same
+  // ones passed to immutable_struct.  INITIALIZER will be a composite
+  // literal of type TYPE.  It will not contain any function calls or
+  // anything else which can not be put into a read-only data section.
+  // It may contain the address of variables created by
+  // immutable_struct.
+  virtual void
+  immutable_struct_set_init(Bvariable*, const std::string& name,
+                           bool is_common, Btype* type, source_location,
+                           Bexpression* initializer) = 0;
+
+  // Create a reference to a named immutable initialized data
+  // structure defined in some other package.  This will be a
+  // structure created by a call to immutable_struct_expression with
+  // the same NAME and TYPE and with IS_COMMON passed as false.  This
+  // corresponds to an extern const global variable in C.
+  virtual Bvariable*
+  immutable_struct_reference(const std::string& name, Btype* type,
+                            source_location) = 0;
+
   // Labels.
   
   // Create a new label.  NAME will be empty if this is a label
index f656acb90ff5c6c8002dec492e91dba4f9e6a8e6..00af29620685bead9d769b687325a4c3109f3985 100644 (file)
@@ -335,7 +335,7 @@ Expression::convert_type_to_interface(Translate_context* context,
   // Otherwise it is the interface method table for RHS_TYPE.
   tree first_field_value;
   if (lhs_is_empty)
-    first_field_value = rhs_type->type_descriptor_pointer(gogo);
+    first_field_value = rhs_type->type_descriptor_pointer(gogo, location);
   else
     {
       // Build the interface method table for this interface and this
@@ -492,7 +492,8 @@ Expression::convert_interface_to_interface(Translate_context* context,
   if (for_type_guard)
     {
       // A type assertion fails when converting a nil interface.
-      tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo);
+      tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo,
+                                                                  location);
       static tree assert_interface_decl;
       tree call = Gogo::call_builtin(&assert_interface_decl,
                                     location,
@@ -524,7 +525,8 @@ Expression::convert_interface_to_interface(Translate_context* context,
       // type assertion converting nil will always succeed.
       go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods")
                 == 0);
-      tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo);
+      tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo,
+                                                                  location);
       static tree convert_interface_decl;
       tree call = Gogo::call_builtin(&convert_interface_decl,
                                     location,
@@ -578,7 +580,7 @@ Expression::convert_interface_to_type(Translate_context* context,
   // will panic with an appropriate runtime type error if the type is
   // not valid.
 
-  tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo);
+  tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo, location);
 
   if (!DECL_P(rhs_tree))
     rhs_tree = save_expr(rhs_tree);
@@ -587,7 +589,8 @@ Expression::convert_interface_to_type(Translate_context* context,
     Expression::get_interface_type_descriptor(context, rhs_type, rhs_tree,
                                              location);
 
-  tree rhs_inter_descriptor = rhs_type->type_descriptor_pointer(gogo);
+  tree rhs_inter_descriptor = rhs_type->type_descriptor_pointer(gogo,
+                                                               location);
 
   static tree check_interface_type_decl;
   tree call = Gogo::call_builtin(&check_interface_type_decl,
@@ -6400,7 +6403,8 @@ Expression::comparison_tree(Translate_context* context, Operator op,
        }
       arg = fold_convert_loc(location, ptr_type_node, arg);
 
-      tree descriptor = right_type->type_descriptor_pointer(context->gogo());
+      tree descriptor = right_type->type_descriptor_pointer(context->gogo(),
+                                                           location);
 
       if (left_type->interface_type()->is_empty())
        {
@@ -12588,7 +12592,10 @@ class Type_descriptor_expression : public Expression
 
   tree
   do_get_tree(Translate_context* context)
-  { return this->type_->type_descriptor_pointer(context->gogo()); }
+  {
+    return this->type_->type_descriptor_pointer(context->gogo(),
+                                               this->location());
+  }
 
  private:
   // The type for which this is the descriptor.
index 8c41f7462e68f2adc4a6d62273924abf8967b1ab..0c5cb671c05c28735e570a3b8520535b707be390 100644 (file)
@@ -959,9 +959,9 @@ Named_object::get_tree(Gogo* gogo, Named_object* function)
            // descriptor, even though we don't do anything with it.
            if (this->package_ == NULL)
              {
-               named_type->type_descriptor_pointer(gogo);
+               named_type->type_descriptor_pointer(gogo, BUILTINS_LOCATION);
                Type* pn = Type::make_pointer_type(named_type);
-               pn->type_descriptor_pointer(gogo);
+               pn->type_descriptor_pointer(gogo, BUILTINS_LOCATION);
              }
          }
       }
@@ -2053,7 +2053,7 @@ Gogo::map_descriptor(Map_type* maptype)
 
   constructor_elt* elt = VEC_quick_push(constructor_elt, descriptor, NULL);
   elt->index = map_descriptor_field;
-  elt->value = maptype->type_descriptor_pointer(this);
+  elt->value = maptype->type_descriptor_pointer(this, BUILTINS_LOCATION);
 
   elt = VEC_quick_push(constructor_elt, descriptor, NULL);
   elt->index = entry_size_field;
@@ -2109,190 +2109,6 @@ Gogo::map_descriptor_type()
                              sizetype);
 }
 
-// Return the name to use for a type descriptor decl for TYPE.  This
-// is used when TYPE does not have a name.
-
-std::string
-Gogo::unnamed_type_descriptor_decl_name(const Type* type)
-{
-  return "__go_td_" + type->mangled_name(this);
-}
-
-// Return the name to use for a type descriptor decl for a type named
-// NAME, defined in the function IN_FUNCTION.  IN_FUNCTION will
-// normally be NULL.
-
-std::string
-Gogo::type_descriptor_decl_name(const Named_object* no,
-                               const Named_object* in_function)
-{
-  std::string ret = "__go_tdn_";
-  if (no->type_value()->is_builtin())
-    go_assert(in_function == NULL);
-  else
-    {
-      const std::string& unique_prefix(no->package() == NULL
-                                      ? this->unique_prefix()
-                                      : no->package()->unique_prefix());
-      const std::string& package_name(no->package() == NULL
-                                     ? this->package_name()
-                                     : no->package()->name());
-      ret.append(unique_prefix);
-      ret.append(1, '.');
-      ret.append(package_name);
-      ret.append(1, '.');
-      if (in_function != NULL)
-       {
-         ret.append(Gogo::unpack_hidden_name(in_function->name()));
-         ret.append(1, '.');
-       }
-    }
-  ret.append(no->name());
-  return ret;
-}
-
-// Where a type descriptor decl should be defined.
-
-Gogo::Type_descriptor_location
-Gogo::type_descriptor_location(const Type* type)
-{
-  const Named_type* name = type->named_type();
-  if (name != NULL)
-    {
-      if (name->named_object()->package() != NULL)
-       {
-         // This is a named type defined in a different package.  The
-         // descriptor should be defined in that package.
-         return TYPE_DESCRIPTOR_UNDEFINED;
-       }
-      else if (name->is_builtin())
-       {
-         // We create the descriptor for a builtin type whenever we
-         // need it.
-         return TYPE_DESCRIPTOR_COMMON;
-       }
-      else
-       {
-         // This is a named type defined in this package.  The
-         // descriptor should be defined here.
-         return TYPE_DESCRIPTOR_DEFINED;
-       }
-    }
-  else
-    {
-      if (type->points_to() != NULL
-         && type->points_to()->named_type() != NULL
-         && type->points_to()->named_type()->named_object()->package() != NULL)
-       {
-         // This is an unnamed pointer to a named type defined in a
-         // different package.  The descriptor should be defined in
-         // that package.
-         return TYPE_DESCRIPTOR_UNDEFINED;
-       }
-      else
-       {
-         // This is an unnamed type.  The descriptor could be defined
-         // in any package where it is needed, and the linker will
-         // pick one descriptor to keep.
-         return TYPE_DESCRIPTOR_COMMON;
-       }
-    }
-}
-
-// Build a type descriptor decl for TYPE.  INITIALIZER is a struct
-// composite literal which initializers the type descriptor.
-
-void
-Gogo::build_type_descriptor_decl(const Type* type, Expression* initializer,
-                                tree* pdecl)
-{
-  const Named_type* name = type->named_type();
-
-  // We can have multiple instances of unnamed types, but we only want
-  // to emit the type descriptor once.  We use a hash table to handle
-  // this.  This is not necessary for named types, as they are unique,
-  // and we store the type descriptor decl in the type itself.
-  tree* phash = NULL;
-  if (name == NULL)
-    {
-      if (this->type_descriptor_decls_ == NULL)
-       this->type_descriptor_decls_ = new Type_descriptor_decls(10);
-
-      std::pair<Type_descriptor_decls::iterator, bool> ins =
-       this->type_descriptor_decls_->insert(std::make_pair(type, NULL_TREE));
-      if (!ins.second)
-       {
-         // We've already built a type descriptor for this type.
-         *pdecl = ins.first->second;
-         return;
-       }
-      phash = &ins.first->second;
-    }
-
-  std::string decl_name;
-  if (name == NULL)
-    decl_name = this->unnamed_type_descriptor_decl_name(type);
-  else
-    decl_name = this->type_descriptor_decl_name(name->named_object(),
-                                               name->in_function());
-  tree id = get_identifier_from_string(decl_name);
-  Type* init_type = initializer->type();
-  tree descriptor_type_tree = type_to_tree(init_type->get_backend(this));
-  if (descriptor_type_tree == error_mark_node)
-    {
-      *pdecl = error_mark_node;
-      return;
-    }
-  tree decl = build_decl(name == NULL ? BUILTINS_LOCATION : name->location(),
-                        VAR_DECL, id,
-                        build_qualified_type(descriptor_type_tree,
-                                             TYPE_QUAL_CONST));
-  TREE_READONLY(decl) = 1;
-  TREE_CONSTANT(decl) = 1;
-  DECL_ARTIFICIAL(decl) = 1;
-
-  go_preserve_from_gc(decl);
-  if (phash != NULL)
-    *phash = decl;
-
-  // We store the new DECL now because we may need to refer to it when
-  // expanding INITIALIZER.
-  *pdecl = decl;
-
-  // If appropriate, just refer to the exported type identifier.
-  Gogo::Type_descriptor_location type_descriptor_location =
-    this->type_descriptor_location(type);
-  if (type_descriptor_location == TYPE_DESCRIPTOR_UNDEFINED)
-    {
-      TREE_PUBLIC(decl) = 1;
-      DECL_EXTERNAL(decl) = 1;
-      return;
-    }
-
-  TREE_STATIC(decl) = 1;
-  TREE_USED(decl) = 1;
-
-  Translate_context context(this, NULL, NULL, NULL);
-  context.set_is_const();
-  tree constructor = initializer->get_tree(&context);
-
-  if (constructor == error_mark_node)
-    go_assert(saw_errors());
-
-  DECL_INITIAL(decl) = constructor;
-
-  if (type_descriptor_location == TYPE_DESCRIPTOR_DEFINED)
-    TREE_PUBLIC(decl) = 1;
-  else
-    {
-      go_assert(type_descriptor_location == TYPE_DESCRIPTOR_COMMON);
-      make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl));
-      resolve_unique_section(decl, 1, 0);
-    }
-
-  rest_of_decl_compilation(decl, 1, 0);
-}
-
 // Build an interface method table for a type: a list of function
 // pointers, one for each interface method.  This is used for
 // interfaces.
@@ -2353,8 +2169,8 @@ Gogo::interface_method_table_for_type(const Interface_type* interface,
     td_type = type;
   else
     td_type = Type::make_pointer_type(type);
-  elt->value = fold_convert(const_ptr_type_node,
-                           td_type->type_descriptor_pointer(this));
+  tree tdp = td_type->type_descriptor_pointer(this, BUILTINS_LOCATION);
+  elt->value = fold_convert(const_ptr_type_node, tdp);
 
   size_t i = 1;
   for (Typed_identifier_list::const_iterator p = interface_methods->begin();
index c3c014e5962ece63a0fcb3febe4b1c541bc07ccb..484d1a11e8fbb44628a8a28e75ddd5e502e0aa82 100644 (file)
@@ -30,7 +30,6 @@ Gogo::Gogo(Backend* backend, int int_type_size, int pointer_size)
     imported_unsafe_(false),
     packages_(),
     map_descriptors_(NULL),
-    type_descriptor_decls_(NULL),
     init_functions_(),
     need_init_fn_(false),
     init_fn_name_(),
index ed9d1eb76f111cad2d4bde8f87ee2bcb3496445d..972369fe6fbdc6cf9739731a5e4d1d7d7c732160 100644 (file)
@@ -483,12 +483,6 @@ class Gogo
   tree
   map_descriptor_type();
 
-  // Build a type descriptor for TYPE using INITIALIZER as the type
-  // descriptor.  This builds a new decl stored in *PDECL.
-  void
-  build_type_descriptor_decl(const Type*, Expression* initializer,
-                            tree* pdecl);
-
   // Build required interface method tables.
   void
   build_interface_method_tables();
@@ -592,32 +586,6 @@ class Gogo
   tree
   ptr_go_string_constant_tree(const std::string&);
 
-  // Return the name to use for a type descriptor decl for an unnamed
-  // type.
-  std::string
-  unnamed_type_descriptor_decl_name(const Type* type);
-
-  // Return the name to use for a type descriptor decl for a type
-  // named NO, defined in IN_FUNCTION.
-  std::string
-  type_descriptor_decl_name(const Named_object* no,
-                           const Named_object* in_function);
-
-  // Where a type descriptor should be defined.
-  enum Type_descriptor_location
-    {
-      // Defined in this file.
-      TYPE_DESCRIPTOR_DEFINED,
-      // Defined in some other file.
-      TYPE_DESCRIPTOR_UNDEFINED,
-      // Common definition which may occur in multiple files.
-      TYPE_DESCRIPTOR_COMMON
-    };
-
-  // Return where the decl for TYPE should be defined.
-  Type_descriptor_location
-  type_descriptor_location(const Type* type);
-
   // Return the type of a trampoline.
   static tree
   trampoline_type_tree();
@@ -635,10 +603,6 @@ class Gogo
   typedef Unordered_map_hash(const Map_type*, tree, Type_hash_identical,
                             Type_identical) Map_descriptors;
 
-  // Map unnamed types to type descriptor decls.
-  typedef Unordered_map_hash(const Type*, tree, Type_hash_identical,
-                            Type_identical) Type_descriptor_decls;
-
   // The backend generator.
   Backend* backend_;
   // The package we are compiling.
@@ -657,8 +621,6 @@ class Gogo
   Packages packages_;
   // Mapping from map types to map descriptors.
   Map_descriptors* map_descriptors_;
-  // Mapping from unnamed types to type descriptor decls.
-  Type_descriptor_decls* type_descriptor_decls_;
   // The functions named "init", if there are any.
   std::vector<Named_object*> init_functions_;
   // Whether we need a magic initialization function.
index 37cca8370e5586a5aeba84ecb2268aeb98b90c08..15e35c2b29d851c5499581a3c58931fc0516d826 100644 (file)
@@ -37,8 +37,7 @@ extern "C"
 // Class Type.
 
 Type::Type(Type_classification classification)
-  : classification_(classification), btype_(NULL),
-    type_descriptor_decl_(NULL_TREE)
+  : classification_(classification), btype_(NULL), type_descriptor_var_(NULL)
 {
 }
 
@@ -926,20 +925,179 @@ Type::do_make_expression_tree(Translate_context*, Expression_list*,
 // Return a pointer to the type descriptor for this type.
 
 tree
-Type::type_descriptor_pointer(Gogo* gogo)
+Type::type_descriptor_pointer(Gogo* gogo, source_location location)
 {
   Type* t = this->forwarded();
-  if (t->type_descriptor_decl_ == NULL_TREE)
+  if (t->type_descriptor_var_ == NULL)
     {
-      Expression* e = t->do_type_descriptor(gogo, NULL);
-      gogo->build_type_descriptor_decl(t, e, &t->type_descriptor_decl_);
-      go_assert(t->type_descriptor_decl_ != NULL_TREE
-                && (t->type_descriptor_decl_ == error_mark_node
-                    || DECL_P(t->type_descriptor_decl_)));
+      t->make_type_descriptor_var(gogo);
+      go_assert(t->type_descriptor_var_ != NULL);
     }
-  if (t->type_descriptor_decl_ == error_mark_node)
+  tree var_tree = var_to_tree(t->type_descriptor_var_);
+  if (var_tree == error_mark_node)
     return error_mark_node;
-  return build_fold_addr_expr(t->type_descriptor_decl_);
+  return build_fold_addr_expr_loc(location, var_tree);
+}
+
+// A mapping from unnamed types to type descriptor variables.
+
+Type::Type_descriptor_vars Type::type_descriptor_vars;
+
+// Build the type descriptor for this type.
+
+void
+Type::make_type_descriptor_var(Gogo* gogo)
+{
+  go_assert(this->type_descriptor_var_ == NULL);
+
+  Named_type* nt = this->named_type();
+
+  // We can have multiple instances of unnamed types, but we only want
+  // to emit the type descriptor once.  We use a hash table.  This is
+  // not necessary for named types, as they are unique, and we store
+  // the type descriptor in the type itself.
+  Bvariable** phash = NULL;
+  if (nt == NULL)
+    {
+      Bvariable* bvnull = NULL;
+      std::pair<Type_descriptor_vars::iterator, bool> ins =
+       Type::type_descriptor_vars.insert(std::make_pair(this, bvnull));
+      if (!ins.second)
+       {
+         // We've already build a type descriptor for this type.
+         this->type_descriptor_var_ = ins.first->second;
+         return;
+       }
+      phash = &ins.first->second;
+    }
+
+  std::string var_name;
+  if (nt == NULL)
+    var_name = this->unnamed_type_descriptor_var_name(gogo);
+  else
+    var_name = this->type_descriptor_var_name(gogo);
+
+  // Build the contents of the type descriptor.
+  Expression* initializer = this->do_type_descriptor(gogo, NULL);
+
+  Btype* initializer_btype = initializer->type()->get_backend(gogo);
+
+  // See if this type descriptor is defined in a different package.
+  bool is_defined_elsewhere = false;
+  if (nt != NULL)
+    {
+      if (nt->named_object()->package() != NULL)
+       {
+         // This is a named type defined in a different package.  The
+         // type descriptor should be defined in that package.
+         is_defined_elsewhere = true;
+       }
+    }
+  else
+    {
+      if (this->points_to() != NULL
+         && this->points_to()->named_type() != NULL
+         && this->points_to()->named_type()->named_object()->package() != NULL)
+       {
+         // This is an unnamed pointer to a named type defined in a
+         // different package.  The descriptor should be defined in
+         // that package.
+         is_defined_elsewhere = true;
+       }
+    }
+
+  source_location loc = nt == NULL ? BUILTINS_LOCATION : nt->location();
+
+  if (is_defined_elsewhere)
+    {
+      this->type_descriptor_var_ =
+       gogo->backend()->immutable_struct_reference(var_name,
+                                                   initializer_btype,
+                                                   loc);
+      if (phash != NULL)
+       *phash = this->type_descriptor_var_;
+      return;
+    }
+
+  // See if this type descriptor can appear in multiple packages.
+  bool is_common = false;
+  if (nt != NULL)
+    {
+      // We create the descriptor for a builtin type whenever we need
+      // it.
+      is_common = nt->is_builtin();
+    }
+  else
+    {
+      // This is an unnamed type.  The descriptor could be defined in
+      // any package where it is needed, and the linker will pick one
+      // descriptor to keep.
+      is_common = true;
+    }
+
+  // We are going to build the type descriptor in this package.  We
+  // must create the variable before we convert the initializer to the
+  // backend representation, because the initializer may refer to the
+  // type descriptor of this type.  By setting type_descriptor_var_ we
+  // ensure that type_descriptor_pointer will work if called while
+  // converting INITIALIZER.
+
+  this->type_descriptor_var_ =
+    gogo->backend()->immutable_struct(var_name, is_common, initializer_btype,
+                                     loc);
+  if (phash != NULL)
+    *phash = this->type_descriptor_var_;
+
+  Translate_context context(gogo, NULL, NULL, NULL);
+  context.set_is_const();
+  Bexpression* binitializer = tree_to_expr(initializer->get_tree(&context));
+
+  gogo->backend()->immutable_struct_set_init(this->type_descriptor_var_,
+                                            var_name, is_common,
+                                            initializer_btype, loc,
+                                            binitializer);
+}
+
+// Return the name of the type descriptor variable for an unnamed
+// type.
+
+std::string
+Type::unnamed_type_descriptor_var_name(Gogo* gogo)
+{
+  return "__go_td_" + this->mangled_name(gogo);
+}
+
+// Return the name of the type descriptor variable for a named type.
+
+std::string
+Type::type_descriptor_var_name(Gogo* gogo)
+{
+  Named_type* nt = this->named_type();
+  Named_object* no = nt->named_object();
+  const Named_object* in_function = nt->in_function();
+  std::string ret = "__go_tdn_";
+  if (nt->is_builtin())
+    go_assert(in_function == NULL);
+  else
+    {
+      const std::string& unique_prefix(no->package() == NULL
+                                      ? gogo->unique_prefix()
+                                      : no->package()->unique_prefix());
+      const std::string& package_name(no->package() == NULL
+                                     ? gogo->package_name()
+                                     : no->package()->name());
+      ret.append(unique_prefix);
+      ret.append(1, '.');
+      ret.append(package_name);
+      ret.append(1, '.');
+      if (in_function != NULL)
+       {
+         ret.append(Gogo::unpack_hidden_name(in_function->name()));
+         ret.append(1, '.');
+       }
+    }
+  ret.append(no->name());
+  return ret;
 }
 
 // Return a composite literal for a type descriptor.
@@ -5114,7 +5272,7 @@ Channel_type::do_make_expression_tree(Translate_context* context,
 
   Type* ptdt = Type::make_type_descriptor_ptr_type();
   tree element_type_descriptor =
-    this->element_type_->type_descriptor_pointer(gogo);
+    this->element_type_->type_descriptor_pointer(gogo, location);
 
   tree bad_index = NULL_TREE;
 
index 23e29dc7522cb59a22d2dc3f5d134a0c0aa1c2e4..fc35431f6ad3fc2f896a372371d050c8ce7b6fa9 100644 (file)
@@ -44,6 +44,7 @@ class Export;
 class Import;
 class Btype;
 class Bexpression;
+class Bvariable;
 
 // Type codes used in type descriptors.  These must match the values
 // in libgo/runtime/go-type.h.  They also match the values in the gc
@@ -832,9 +833,10 @@ class Type
   { return this->do_make_expression_tree(context, args, location); }
 
   // Build a type descriptor entry for this type.  Return a pointer to
-  // it.
+  // it.  The location is the location which causes us to need the
+  // entry.
   tree
-  type_descriptor_pointer(Gogo* gogo);
+  type_descriptor_pointer(Gogo* gogo, source_location);
 
   // Return the type reflection string for this type.
   std::string
@@ -1010,6 +1012,25 @@ class Type
   are_assignable_check_hidden(const Type* lhs, const Type* rhs,
                              bool check_hidden_fields, std::string* reason);
 
+  // Map unnamed types to type descriptor decls.
+  typedef Unordered_map_hash(const Type*, Bvariable*, Type_hash_identical,
+                            Type_identical) Type_descriptor_vars;
+
+  static Type_descriptor_vars type_descriptor_vars;
+
+  // Build the type descriptor variable for this type.
+  void
+  make_type_descriptor_var(Gogo*);
+
+  // Return the name of the type descriptor variable for an unnamed
+  // type.
+  std::string
+  unnamed_type_descriptor_var_name(Gogo*);
+
+  // Return the name of the type descriptor variable for a named type.
+  std::string
+  type_descriptor_var_name(Gogo*);
+
   // Get the hash and equality functions for a type.
   void
   type_functions(const char** hash_fn, const char** equal_fn) const;
@@ -1101,9 +1122,9 @@ class Type
   // The backend representation of the type, once it has been
   // determined.
   Btype* btype_;
-  // The decl for the type descriptor for this type.  This starts out
-  // as NULL and is filled in as needed.
-  tree type_descriptor_decl_;
+  // The type descriptor for this type.  This starts out as NULL and
+  // is filled in as needed.
+  Bvariable* type_descriptor_var_;
 };
 
 // Type hash table operations.