compiler: Don't initialize zero sized variables.
authorIan Lance Taylor <iant@google.com>
Thu, 8 Mar 2012 23:33:04 +0000 (23:33 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Thu, 8 Mar 2012 23:33:04 +0000 (23:33 +0000)
* 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

gcc/go/ChangeLog
gcc/go/config-lang.in
gcc/go/go-c.h
gcc/go/go-gcc.cc
gcc/go/gofrontend/gogo-tree.cc

index 8b8e90c4b6896ae9f2a73bbd3e868a996aff4c22..2c0b3c233369a0982a37deb095ba7c1417569169 100644 (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.
index 4b5886eb758cc20b6dd7a597606668339f1a9693..586e070e7d1e49dae7708c3eb21059ea4ba0074f 100644 (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"
index 0bfed85322a6e65332577d1446fa225b40d211fd..e123d52d8d1dc5ac90a38312b7dc948387c23350 100644 (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
index a19bb894a993284c78d57ea05cc3109c5b613c9c..0cc167d4ba7bbfdb5dd6bca04aa85273aa68de60 100644 (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);
index 603b97ec0c1e89a7fa2f3602cefd191852d4c9a9..fa229320c963d9616a80ffa31cb7ca4a00493e35 100644 (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(),