mirror of git://gcc.gnu.org/git/gcc.git
Use backend interface for type descriptors.
* 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
This commit is contained in:
parent
ba68a139ac
commit
70f910247b
|
@ -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>
|
2011-06-09 Ian Lance Taylor <iant@google.com>
|
||||||
|
|
||||||
* go-gcc.cc (Gcc_backend::zero_expression): New function.
|
* go-gcc.cc (Gcc_backend::zero_expression): New function.
|
||||||
|
|
|
@ -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
|
GOINCLUDES = -I $(srcdir)/go -I $(srcdir)/go/gofrontend
|
||||||
|
|
||||||
go/go-gcc.o: go/go-gcc.cc $(GO_SYSTEM_H) $(TREE_H) tree-iterator.h \
|
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)
|
$(CXX) -c $(GOINCLUDES) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) $< $(OUTPUT_OPTION)
|
||||||
|
|
||||||
go/%.o: go/gofrontend/%.cc
|
go/%.o: go/gofrontend/%.cc
|
||||||
|
|
|
@ -32,6 +32,7 @@ extern "C"
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
#include "tree-iterator.h"
|
#include "tree-iterator.h"
|
||||||
#include "gimple.h"
|
#include "gimple.h"
|
||||||
|
#include "toplev.h"
|
||||||
|
|
||||||
#ifndef ENABLE_BUILD_WITH_CXX
|
#ifndef ENABLE_BUILD_WITH_CXX
|
||||||
}
|
}
|
||||||
|
@ -276,6 +277,16 @@ class Gcc_backend : public Backend
|
||||||
temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression*, bool,
|
temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression*, bool,
|
||||||
source_location, Bstatement**);
|
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.
|
// Labels.
|
||||||
|
|
||||||
Blabel*
|
Blabel*
|
||||||
|
@ -1198,6 +1209,83 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock,
|
||||||
return new Bvariable(var);
|
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.
|
// Make a label.
|
||||||
|
|
||||||
Blabel*
|
Blabel*
|
||||||
|
|
|
@ -361,6 +361,52 @@ class Backend
|
||||||
bool address_is_taken, source_location location,
|
bool address_is_taken, source_location location,
|
||||||
Bstatement** pstatement) = 0;
|
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.
|
// Labels.
|
||||||
|
|
||||||
// Create a new label. NAME will be empty if this is a label
|
// Create a new label. NAME will be empty if this is a label
|
||||||
|
|
|
@ -335,7 +335,7 @@ Expression::convert_type_to_interface(Translate_context* context,
|
||||||
// Otherwise it is the interface method table for RHS_TYPE.
|
// Otherwise it is the interface method table for RHS_TYPE.
|
||||||
tree first_field_value;
|
tree first_field_value;
|
||||||
if (lhs_is_empty)
|
if (lhs_is_empty)
|
||||||
first_field_value = rhs_type->type_descriptor_pointer(gogo);
|
first_field_value = rhs_type->type_descriptor_pointer(gogo, location);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Build the interface method table for this interface and this
|
// 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)
|
if (for_type_guard)
|
||||||
{
|
{
|
||||||
// A type assertion fails when converting a nil interface.
|
// 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;
|
static tree assert_interface_decl;
|
||||||
tree call = Gogo::call_builtin(&assert_interface_decl,
|
tree call = Gogo::call_builtin(&assert_interface_decl,
|
||||||
location,
|
location,
|
||||||
|
@ -524,7 +525,8 @@ Expression::convert_interface_to_interface(Translate_context* context,
|
||||||
// type assertion converting nil will always succeed.
|
// type assertion converting nil will always succeed.
|
||||||
go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods")
|
go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods")
|
||||||
== 0);
|
== 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;
|
static tree convert_interface_decl;
|
||||||
tree call = Gogo::call_builtin(&convert_interface_decl,
|
tree call = Gogo::call_builtin(&convert_interface_decl,
|
||||||
location,
|
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
|
// will panic with an appropriate runtime type error if the type is
|
||||||
// not valid.
|
// 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))
|
if (!DECL_P(rhs_tree))
|
||||||
rhs_tree = save_expr(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,
|
Expression::get_interface_type_descriptor(context, rhs_type, rhs_tree,
|
||||||
location);
|
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;
|
static tree check_interface_type_decl;
|
||||||
tree call = Gogo::call_builtin(&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);
|
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())
|
if (left_type->interface_type()->is_empty())
|
||||||
{
|
{
|
||||||
|
@ -12588,7 +12592,10 @@ class Type_descriptor_expression : public Expression
|
||||||
|
|
||||||
tree
|
tree
|
||||||
do_get_tree(Translate_context* context)
|
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:
|
private:
|
||||||
// The type for which this is the descriptor.
|
// The type for which this is the descriptor.
|
||||||
|
|
|
@ -959,9 +959,9 @@ Named_object::get_tree(Gogo* gogo, Named_object* function)
|
||||||
// descriptor, even though we don't do anything with it.
|
// descriptor, even though we don't do anything with it.
|
||||||
if (this->package_ == NULL)
|
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);
|
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);
|
constructor_elt* elt = VEC_quick_push(constructor_elt, descriptor, NULL);
|
||||||
elt->index = map_descriptor_field;
|
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 = VEC_quick_push(constructor_elt, descriptor, NULL);
|
||||||
elt->index = entry_size_field;
|
elt->index = entry_size_field;
|
||||||
|
@ -2109,190 +2109,6 @@ Gogo::map_descriptor_type()
|
||||||
sizetype);
|
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
|
// Build an interface method table for a type: a list of function
|
||||||
// pointers, one for each interface method. This is used for
|
// pointers, one for each interface method. This is used for
|
||||||
// interfaces.
|
// interfaces.
|
||||||
|
@ -2353,8 +2169,8 @@ Gogo::interface_method_table_for_type(const Interface_type* interface,
|
||||||
td_type = type;
|
td_type = type;
|
||||||
else
|
else
|
||||||
td_type = Type::make_pointer_type(type);
|
td_type = Type::make_pointer_type(type);
|
||||||
elt->value = fold_convert(const_ptr_type_node,
|
tree tdp = td_type->type_descriptor_pointer(this, BUILTINS_LOCATION);
|
||||||
td_type->type_descriptor_pointer(this));
|
elt->value = fold_convert(const_ptr_type_node, tdp);
|
||||||
|
|
||||||
size_t i = 1;
|
size_t i = 1;
|
||||||
for (Typed_identifier_list::const_iterator p = interface_methods->begin();
|
for (Typed_identifier_list::const_iterator p = interface_methods->begin();
|
||||||
|
|
|
@ -30,7 +30,6 @@ Gogo::Gogo(Backend* backend, int int_type_size, int pointer_size)
|
||||||
imported_unsafe_(false),
|
imported_unsafe_(false),
|
||||||
packages_(),
|
packages_(),
|
||||||
map_descriptors_(NULL),
|
map_descriptors_(NULL),
|
||||||
type_descriptor_decls_(NULL),
|
|
||||||
init_functions_(),
|
init_functions_(),
|
||||||
need_init_fn_(false),
|
need_init_fn_(false),
|
||||||
init_fn_name_(),
|
init_fn_name_(),
|
||||||
|
|
|
@ -483,12 +483,6 @@ class Gogo
|
||||||
tree
|
tree
|
||||||
map_descriptor_type();
|
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.
|
// Build required interface method tables.
|
||||||
void
|
void
|
||||||
build_interface_method_tables();
|
build_interface_method_tables();
|
||||||
|
@ -592,32 +586,6 @@ class Gogo
|
||||||
tree
|
tree
|
||||||
ptr_go_string_constant_tree(const std::string&);
|
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.
|
// Return the type of a trampoline.
|
||||||
static tree
|
static tree
|
||||||
trampoline_type_tree();
|
trampoline_type_tree();
|
||||||
|
@ -635,10 +603,6 @@ class Gogo
|
||||||
typedef Unordered_map_hash(const Map_type*, tree, Type_hash_identical,
|
typedef Unordered_map_hash(const Map_type*, tree, Type_hash_identical,
|
||||||
Type_identical) Map_descriptors;
|
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.
|
// The backend generator.
|
||||||
Backend* backend_;
|
Backend* backend_;
|
||||||
// The package we are compiling.
|
// The package we are compiling.
|
||||||
|
@ -657,8 +621,6 @@ class Gogo
|
||||||
Packages packages_;
|
Packages packages_;
|
||||||
// Mapping from map types to map descriptors.
|
// Mapping from map types to map descriptors.
|
||||||
Map_descriptors* 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.
|
// The functions named "init", if there are any.
|
||||||
std::vector<Named_object*> init_functions_;
|
std::vector<Named_object*> init_functions_;
|
||||||
// Whether we need a magic initialization function.
|
// Whether we need a magic initialization function.
|
||||||
|
|
|
@ -37,8 +37,7 @@ extern "C"
|
||||||
// Class Type.
|
// Class Type.
|
||||||
|
|
||||||
Type::Type(Type_classification classification)
|
Type::Type(Type_classification classification)
|
||||||
: classification_(classification), btype_(NULL),
|
: classification_(classification), btype_(NULL), type_descriptor_var_(NULL)
|
||||||
type_descriptor_decl_(NULL_TREE)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -926,20 +925,179 @@ Type::do_make_expression_tree(Translate_context*, Expression_list*,
|
||||||
// Return a pointer to the type descriptor for this type.
|
// Return a pointer to the type descriptor for this type.
|
||||||
|
|
||||||
tree
|
tree
|
||||||
Type::type_descriptor_pointer(Gogo* gogo)
|
Type::type_descriptor_pointer(Gogo* gogo, source_location location)
|
||||||
{
|
{
|
||||||
Type* t = this->forwarded();
|
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);
|
t->make_type_descriptor_var(gogo);
|
||||||
gogo->build_type_descriptor_decl(t, e, &t->type_descriptor_decl_);
|
go_assert(t->type_descriptor_var_ != NULL);
|
||||||
go_assert(t->type_descriptor_decl_ != NULL_TREE
|
|
||||||
&& (t->type_descriptor_decl_ == error_mark_node
|
|
||||||
|| DECL_P(t->type_descriptor_decl_)));
|
|
||||||
}
|
}
|
||||||
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 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.
|
// 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();
|
Type* ptdt = Type::make_type_descriptor_ptr_type();
|
||||||
tree element_type_descriptor =
|
tree element_type_descriptor =
|
||||||
this->element_type_->type_descriptor_pointer(gogo);
|
this->element_type_->type_descriptor_pointer(gogo, location);
|
||||||
|
|
||||||
tree bad_index = NULL_TREE;
|
tree bad_index = NULL_TREE;
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ class Export;
|
||||||
class Import;
|
class Import;
|
||||||
class Btype;
|
class Btype;
|
||||||
class Bexpression;
|
class Bexpression;
|
||||||
|
class Bvariable;
|
||||||
|
|
||||||
// Type codes used in type descriptors. These must match the values
|
// 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
|
// 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); }
|
{ return this->do_make_expression_tree(context, args, location); }
|
||||||
|
|
||||||
// Build a type descriptor entry for this type. Return a pointer to
|
// 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
|
tree
|
||||||
type_descriptor_pointer(Gogo* gogo);
|
type_descriptor_pointer(Gogo* gogo, source_location);
|
||||||
|
|
||||||
// Return the type reflection string for this type.
|
// Return the type reflection string for this type.
|
||||||
std::string
|
std::string
|
||||||
|
@ -1010,6 +1012,25 @@ class Type
|
||||||
are_assignable_check_hidden(const Type* lhs, const Type* rhs,
|
are_assignable_check_hidden(const Type* lhs, const Type* rhs,
|
||||||
bool check_hidden_fields, std::string* reason);
|
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.
|
// Get the hash and equality functions for a type.
|
||||||
void
|
void
|
||||||
type_functions(const char** hash_fn, const char** equal_fn) const;
|
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
|
// The backend representation of the type, once it has been
|
||||||
// determined.
|
// determined.
|
||||||
Btype* btype_;
|
Btype* btype_;
|
||||||
// The decl for the type descriptor for this type. This starts out
|
// The type descriptor for this type. This starts out as NULL and
|
||||||
// as NULL and is filled in as needed.
|
// is filled in as needed.
|
||||||
tree type_descriptor_decl_;
|
Bvariable* type_descriptor_var_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Type hash table operations.
|
// Type hash table operations.
|
||||||
|
|
Loading…
Reference in New Issue