aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/go/ChangeLog8
-rw-r--r--gcc/go/Make-lang.in3
-rw-r--r--gcc/go/go-gcc.cc88
-rw-r--r--gcc/go/gofrontend/backend.h46
-rw-r--r--gcc/go/gofrontend/expressions.cc21
-rw-r--r--gcc/go/gofrontend/gogo-tree.cc194
-rw-r--r--gcc/go/gofrontend/gogo.cc1
-rw-r--r--gcc/go/gofrontend/gogo.h38
-rw-r--r--gcc/go/gofrontend/types.cc182
-rw-r--r--gcc/go/gofrontend/types.h31
10 files changed, 359 insertions, 253 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog
index aac428b..11abbbc 100644
--- a/gcc/go/ChangeLog
+++ b/gcc/go/ChangeLog
@@ -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.
diff --git a/gcc/go/Make-lang.in b/gcc/go/Make-lang.in
index ef5dc75..61a0f3c 100644
--- a/gcc/go/Make-lang.in
+++ b/gcc/go/Make-lang.in
@@ -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
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index 1299e9b..dbdf95f 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -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*
diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h
index 5ece2e6..b18c18c 100644
--- a/gcc/go/gofrontend/backend.h
+++ b/gcc/go/gofrontend/backend.h
@@ -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
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index f656acb..00af296 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -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.
diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc
index 8c41f74..0c5cb67 100644
--- a/gcc/go/gofrontend/gogo-tree.cc
+++ b/gcc/go/gofrontend/gogo-tree.cc
@@ -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();
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index c3c014e..484d1a1 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -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_(),
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index ed9d1eb..972369f 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -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.
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index 37cca83..15e35c2 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -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;
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
index 23e29dc..fc35431 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -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.