aboutsummaryrefslogtreecommitdiff
path: root/gcc/go/go-gcc.cc
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2012-03-08 23:33:04 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2012-03-08 23:33:04 +0000
commit7d6be4c870c2a1fdb694222ee1f750badc3b3d8a (patch)
tree7a5ccba6a082f2d0a7ecff65d3eef03f31a471da /gcc/go/go-gcc.cc
parentb97190553d2798af4c5c8e6e775b942e458ba09e (diff)
downloadgcc-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.cc85
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);