diff options
author | Ian Lance Taylor <iant@google.com> | 2012-03-08 23:33:04 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-03-08 23:33:04 +0000 |
commit | 7d6be4c870c2a1fdb694222ee1f750badc3b3d8a (patch) | |
tree | 7a5ccba6a082f2d0a7ecff65d3eef03f31a471da /gcc/go/go-gcc.cc | |
parent | b97190553d2798af4c5c8e6e775b942e458ba09e (diff) | |
download | gcc-7d6be4c870c2a1fdb694222ee1f750badc3b3d8a.zip gcc-7d6be4c870c2a1fdb694222ee1f750badc3b3d8a.tar.gz gcc-7d6be4c870c2a1fdb694222ee1f750badc3b3d8a.tar.bz2 |
compiler: Don't initialize zero sized variables.
* 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.
From-SVN: r185115
Diffstat (limited to 'gcc/go/go-gcc.cc')
-rw-r--r-- | gcc/go/go-gcc.cc | 85 |
1 files changed, 82 insertions, 3 deletions
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index a19bb89..0cc167d 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,18 @@ 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)); + return this->make_statement(fold_build2_loc(location.gcc_location(), MODIFY_EXPR, void_type_node, @@ -1178,6 +1211,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 +1268,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); |