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
This commit is contained in:
Ian Lance Taylor 2012-03-08 23:33:04 +00:00 committed by Ian Lance Taylor
parent b97190553d
commit 7d6be4c870
5 changed files with 99 additions and 5 deletions

View File

@ -1,3 +1,14 @@
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.

View File

@ -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"

View File

@ -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

View File

@ -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);

View File

@ -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(),