diff options
author | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-03-15 09:35:56 +0000 |
---|---|---|
committer | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-03-15 09:35:56 +0000 |
commit | e8844fc36936140eb1c9f659a16b401980733b49 (patch) | |
tree | 604287ecd222a7298e95b6799dafc8e1b6467250 /gcc/go | |
parent | 5ce2a6ec8443c9fcf3c4f96383246efa8f5b3d6a (diff) | |
download | gcc-e8844fc36936140eb1c9f659a16b401980733b49.tar.gz |
2012-03-15 Basile Starynkevitch <basile@starynkevitch.net>
MELT branch merged with trunk rev 185416 using svnmerge
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@185423 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/go')
-rw-r--r-- | gcc/go/ChangeLog | 16 | ||||
-rw-r--r-- | gcc/go/config-lang.in | 2 | ||||
-rw-r--r-- | gcc/go/go-c.h | 2 | ||||
-rw-r--r-- | gcc/go/go-gcc.cc | 109 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 15 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo-tree.cc | 4 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 5 |
7 files changed, 139 insertions, 14 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 8b8e90c4b68..f779e9b89cf 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,19 @@ +2012-03-09 Ian Lance Taylor <iant@google.com> + + * go-gcc.cc (Gcc_backend::assignment_statement): Convert the rhs + to the lhs type if necessary. + +2012-03-08 Ian Lance Taylor <iant@google.com> + + * go-gcc.cc (Gcc_backend::init_statement): Don't initialize a + zero-sized variable. + (go_non_zero_struct): New global variable. + (Gcc_backend::non_zero_size_type): New function. + (Gcc_backend::global_variable): Don't build an assignment for a + zero-sized value. + * go-c.h (go_non_zero_struct): Declare. + * config-lang.in (gtfiles): Add go-c.h. + 2012-02-29 Ian Lance Taylor <iant@google.com> * go-gcc.cc (class Gcc_tree): Add set_tree method. diff --git a/gcc/go/config-lang.in b/gcc/go/config-lang.in index 4b5886eb758..586e070e7d1 100644 --- a/gcc/go/config-lang.in +++ b/gcc/go/config-lang.in @@ -34,7 +34,7 @@ target_libs="target-libgo target-libffi" # compiler during stage 1. lang_requires_boot_languages=c++ -gtfiles="\$(srcdir)/go/go-lang.c" +gtfiles="\$(srcdir)/go/go-lang.c \$(srcdir)/go/go-c.h" # Do not build by default. build_by_default="no" diff --git a/gcc/go/go-c.h b/gcc/go/go-c.h index 0bfed85322a..e123d52d8d1 100644 --- a/gcc/go/go-c.h +++ b/gcc/go/go-c.h @@ -69,6 +69,8 @@ extern void go_write_export_data (const char *, unsigned int); extern const char *go_read_export_data (int, off_t, char **, size_t *, int *); +extern GTY(()) tree go_non_zero_struct; + #if defined(__cplusplus) && !defined(ENABLE_BUILD_WITH_CXX) } /* End extern "C". */ #endif diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index a19bb894a99..96c171835c4 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -338,6 +338,9 @@ class Gcc_backend : public Backend Btype* fill_in_array(Btype*, Btype*, Bexpression*); + + tree + non_zero_size_type(tree); }; // A helper function. @@ -870,9 +873,27 @@ Gcc_backend::init_statement(Bvariable* var, Bexpression* init) if (var_tree == error_mark_node || init_tree == error_mark_node) return this->error_statement(); gcc_assert(TREE_CODE(var_tree) == VAR_DECL); - DECL_INITIAL(var_tree) = init_tree; - return this->make_statement(build1_loc(DECL_SOURCE_LOCATION(var_tree), - DECL_EXPR, void_type_node, var_tree)); + + // To avoid problems with GNU ld, we don't make zero-sized + // externally visible variables. That might lead us to doing an + // initialization of a zero-sized expression to a non-zero sized + // variable, or vice-versa. Avoid crashes by omitting the + // initializer. Such initializations don't mean anything anyhow. + if (int_size_in_bytes(TREE_TYPE(var_tree)) != 0 + && init_tree != NULL_TREE + && int_size_in_bytes(TREE_TYPE(init_tree)) != 0) + { + DECL_INITIAL(var_tree) = init_tree; + init_tree = NULL_TREE; + } + + tree ret = build1_loc(DECL_SOURCE_LOCATION(var_tree), DECL_EXPR, + void_type_node, var_tree); + if (init_tree != NULL_TREE) + ret = build2_loc(DECL_SOURCE_LOCATION(var_tree), COMPOUND_EXPR, + void_type_node, init_tree, ret); + + return this->make_statement(ret); } // Assignment. @@ -885,6 +906,42 @@ Gcc_backend::assignment_statement(Bexpression* lhs, Bexpression* rhs, tree rhs_tree = rhs->get_tree(); if (lhs_tree == error_mark_node || rhs_tree == error_mark_node) return this->error_statement(); + + // To avoid problems with GNU ld, we don't make zero-sized + // externally visible variables. That might lead us to doing an + // assignment of a zero-sized expression to a non-zero sized + // expression; avoid crashes here by avoiding assignments of + // zero-sized expressions. Such assignments don't really mean + // anything anyhow. + if (int_size_in_bytes(TREE_TYPE(lhs_tree)) == 0 + || int_size_in_bytes(TREE_TYPE(rhs_tree)) == 0) + return this->compound_statement(this->expression_statement(lhs), + this->expression_statement(rhs)); + + // Sometimes the same unnamed Go type can be created multiple times + // and thus have multiple tree representations. Make sure this does + // not confuse the middle-end. + if (TREE_TYPE(lhs_tree) != TREE_TYPE(rhs_tree)) + { + tree lhs_type_tree = TREE_TYPE(lhs_tree); + gcc_assert(TREE_CODE(lhs_type_tree) == TREE_CODE(TREE_TYPE(rhs_tree))); + if (POINTER_TYPE_P(lhs_type_tree) + || INTEGRAL_TYPE_P(lhs_type_tree) + || SCALAR_FLOAT_TYPE_P(lhs_type_tree) + || COMPLEX_FLOAT_TYPE_P(lhs_type_tree)) + rhs_tree = fold_convert_loc(location.gcc_location(), lhs_type_tree, + rhs_tree); + else if (TREE_CODE(lhs_type_tree) == RECORD_TYPE + || TREE_CODE(lhs_type_tree) == ARRAY_TYPE) + { + gcc_assert(int_size_in_bytes(lhs_type_tree) + == int_size_in_bytes(TREE_TYPE(rhs_tree))); + rhs_tree = fold_build1_loc(location.gcc_location(), + VIEW_CONVERT_EXPR, + lhs_type_tree, rhs_tree); + } + } + return this->make_statement(fold_build2_loc(location.gcc_location(), MODIFY_EXPR, void_type_node, @@ -1178,6 +1235,48 @@ Gcc_backend::block_statement(Bblock* bblock) return this->make_statement(bind_tree); } +// This is not static because we declare it with GTY(()) in go-c.h. +tree go_non_zero_struct; + +// Return a type corresponding to TYPE with non-zero size. + +tree +Gcc_backend::non_zero_size_type(tree type) +{ + if (int_size_in_bytes(type) != 0) + return type; + + switch (TREE_CODE(type)) + { + case RECORD_TYPE: + { + if (go_non_zero_struct == NULL_TREE) + { + type = make_node(RECORD_TYPE); + tree field = build_decl(UNKNOWN_LOCATION, FIELD_DECL, + get_identifier("dummy"), + boolean_type_node); + DECL_CONTEXT(field) = type; + TYPE_FIELDS(type) = field; + layout_type(type); + go_non_zero_struct = type; + } + return go_non_zero_struct; + } + + case ARRAY_TYPE: + { + tree element_type = non_zero_size_type(TREE_TYPE(type)); + return build_array_type_nelts(element_type, 1); + } + + default: + gcc_unreachable(); + } + + gcc_unreachable(); +} + // Make a global variable. Bvariable* @@ -1193,6 +1292,10 @@ Gcc_backend::global_variable(const std::string& package_name, if (type_tree == error_mark_node) return this->error_variable(); + // The GNU linker does not like dynamic variables with zero size. + if ((is_external || !is_hidden) && int_size_in_bytes(type_tree) == 0) + type_tree = this->non_zero_size_type(type_tree); + std::string var_name(package_name); var_name.push_back('.'); var_name.append(name); diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 134b5ae2aae..90cf6f32dab 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -205,9 +205,6 @@ Expression::convert_for_assignment(Translate_context* context, Type* lhs_type, Type* rhs_type, tree rhs_tree, Location location) { - if (lhs_type == rhs_type) - return rhs_tree; - if (lhs_type->is_error() || rhs_type->is_error()) return error_mark_node; @@ -220,7 +217,7 @@ Expression::convert_for_assignment(Translate_context* context, Type* lhs_type, if (lhs_type_tree == error_mark_node) return error_mark_node; - if (lhs_type->interface_type() != NULL) + if (lhs_type != rhs_type && lhs_type->interface_type() != NULL) { if (rhs_type->interface_type() == NULL) return Expression::convert_type_to_interface(context, lhs_type, @@ -231,7 +228,7 @@ Expression::convert_for_assignment(Translate_context* context, Type* lhs_type, rhs_type, rhs_tree, false, location); } - else if (rhs_type->interface_type() != NULL) + else if (lhs_type != rhs_type && rhs_type->interface_type() != NULL) return Expression::convert_interface_to_type(context, lhs_type, rhs_type, rhs_tree, location); else if (lhs_type->is_slice_type() && rhs_type->is_nil_type()) @@ -289,10 +286,16 @@ Expression::convert_for_assignment(Translate_context* context, Type* lhs_type, || (TREE_CODE(lhs_type_tree) == ARRAY_TYPE && TREE_CODE(TREE_TYPE(rhs_tree)) == ARRAY_TYPE)) { + // Avoid confusion from zero sized variables which may be + // represented as non-zero-sized. + if (int_size_in_bytes(lhs_type_tree) == 0 + || int_size_in_bytes(TREE_TYPE(rhs_tree)) == 0) + return rhs_tree; + // This conversion must be permitted by Go, or we wouldn't have // gotten here. go_assert(int_size_in_bytes(lhs_type_tree) - == int_size_in_bytes(TREE_TYPE(rhs_tree))); + == int_size_in_bytes(TREE_TYPE(rhs_tree))); return fold_build1_loc(location.gcc_location(), VIEW_CONVERT_EXPR, lhs_type_tree, rhs_tree); } diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc index 603b97ec0c1..fa229320c96 100644 --- a/gcc/go/gofrontend/gogo-tree.cc +++ b/gcc/go/gofrontend/gogo-tree.cc @@ -843,7 +843,9 @@ Gogo::write_globals() this->backend()->global_variable_set_init(var, tree_to_expr(init)); } - else if (is_sink) + else if (is_sink + || int_size_in_bytes(TREE_TYPE(init)) == 0 + || int_size_in_bytes(TREE_TYPE(vec[i])) == 0) var_init_tree = init; else var_init_tree = fold_build2_loc(no->location().gcc_location(), diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index ca57aea26ee..5fe5aead9c0 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -628,7 +628,7 @@ Gogo::start_function(const std::string& name, Function_type* type, Variable* this_param = new Variable(receiver->type(), NULL, false, true, true, location); std::string rname = receiver->name(); - if (rname.empty()) + if (rname.empty() || Gogo::is_sink_name(rname)) { // We need to give receivers a name since they wind up in // DECL_ARGUMENTS. FIXME. @@ -638,8 +638,7 @@ Gogo::start_function(const std::string& name, Function_type* type, ++count; rname = buf; } - if (!Gogo::is_sink_name(rname)) - block->bindings()->add_variable(rname, NULL, this_param); + block->bindings()->add_variable(rname, NULL, this_param); } const Typed_identifier_list* parameters = type->parameters(); |