Commit 7d6be4c8 by Ian Lance Taylor Committed by Ian Lance Taylor

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
parent b9719055
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> 2012-02-29 Ian Lance Taylor <iant@google.com>
* go-gcc.cc (class Gcc_tree): Add set_tree method. * go-gcc.cc (class Gcc_tree): Add set_tree method.
......
...@@ -34,7 +34,7 @@ target_libs="target-libgo target-libffi" ...@@ -34,7 +34,7 @@ target_libs="target-libgo target-libffi"
# compiler during stage 1. # compiler during stage 1.
lang_requires_boot_languages=c++ 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. # Do not build by default.
build_by_default="no" build_by_default="no"
...@@ -69,6 +69,8 @@ extern void go_write_export_data (const char *, unsigned int); ...@@ -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 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) #if defined(__cplusplus) && !defined(ENABLE_BUILD_WITH_CXX)
} /* End extern "C". */ } /* End extern "C". */
#endif #endif
......
...@@ -338,6 +338,9 @@ class Gcc_backend : public Backend ...@@ -338,6 +338,9 @@ class Gcc_backend : public Backend
Btype* Btype*
fill_in_array(Btype*, Btype*, Bexpression*); fill_in_array(Btype*, Btype*, Bexpression*);
tree
non_zero_size_type(tree);
}; };
// A helper function. // A helper function.
...@@ -870,9 +873,27 @@ Gcc_backend::init_statement(Bvariable* var, Bexpression* init) ...@@ -870,9 +873,27 @@ Gcc_backend::init_statement(Bvariable* var, Bexpression* init)
if (var_tree == error_mark_node || init_tree == error_mark_node) if (var_tree == error_mark_node || init_tree == error_mark_node)
return this->error_statement(); return this->error_statement();
gcc_assert(TREE_CODE(var_tree) == VAR_DECL); 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), // To avoid problems with GNU ld, we don't make zero-sized
DECL_EXPR, void_type_node, var_tree)); // 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. // Assignment.
...@@ -885,6 +906,18 @@ Gcc_backend::assignment_statement(Bexpression* lhs, Bexpression* rhs, ...@@ -885,6 +906,18 @@ Gcc_backend::assignment_statement(Bexpression* lhs, Bexpression* rhs,
tree rhs_tree = rhs->get_tree(); tree rhs_tree = rhs->get_tree();
if (lhs_tree == error_mark_node || rhs_tree == error_mark_node) if (lhs_tree == error_mark_node || rhs_tree == error_mark_node)
return this->error_statement(); 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(), return this->make_statement(fold_build2_loc(location.gcc_location(),
MODIFY_EXPR, MODIFY_EXPR,
void_type_node, void_type_node,
...@@ -1178,6 +1211,48 @@ Gcc_backend::block_statement(Bblock* bblock) ...@@ -1178,6 +1211,48 @@ Gcc_backend::block_statement(Bblock* bblock)
return this->make_statement(bind_tree); 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. // Make a global variable.
Bvariable* Bvariable*
...@@ -1193,6 +1268,10 @@ Gcc_backend::global_variable(const std::string& package_name, ...@@ -1193,6 +1268,10 @@ Gcc_backend::global_variable(const std::string& package_name,
if (type_tree == error_mark_node) if (type_tree == error_mark_node)
return this->error_variable(); 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); std::string var_name(package_name);
var_name.push_back('.'); var_name.push_back('.');
var_name.append(name); var_name.append(name);
......
...@@ -843,7 +843,9 @@ Gogo::write_globals() ...@@ -843,7 +843,9 @@ Gogo::write_globals()
this->backend()->global_variable_set_init(var, this->backend()->global_variable_set_init(var,
tree_to_expr(init)); 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; var_init_tree = init;
else else
var_init_tree = fold_build2_loc(no->location().gcc_location(), var_init_tree = fold_build2_loc(no->location().gcc_location(),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment