diff mbox

libgo patch committed: treat functions that return zero bytes as returning void

Message ID CAOyqgcWM-ZnLp2TYUSQxJHqP5ywE1XybrXVS13_FcfKF6Skkgg@mail.gmail.com
State New
Headers show

Commit Message

Ian Lance Taylor Aug. 8, 2016, 7:53 p.m. UTC
PR 72814 is a bug that is due to a mismatch between libffi and the
code being called when the code returns a zero-sized struct.  libffi
can not represent a zero-sized struct, so the Go runtime creates a
libffi type that uses a one-byte struct.  This technique fails on
32-bit SPARC, where the calling convention for a zero-sized struct is
different than the calling convention for a one-byte struct; calls to
the latter function are followed by an unimp instruction, calls to the
former are not.

This patch fixes the problem by treating functions that return zero
result byte as though they actually return void.  The change is to the
GCC interface and the libffi interface used by the gofrontend.

For this patch bootstrapped on x86_64-pc-linux-gnu and
sparc-sun-solaris.  Ran the full Go testsuite on x86_64-pc-linux-gnu
and the reflect package tests on sparc-sun-solaris.  Committed to
mainline.

Ian

2016-08-08  Ian Lance Taylor  <iant@google.com>

PR go/72814
* go-gcc.cc (Gcc_backend::function_type): If the return type is
zero bytes, treat the function as returning void.
(return_statement): If the return type is zero bytes, don't
actually return any values.
diff mbox

Patch

Index: gcc/go/go-gcc.cc
===================================================================
--- gcc/go/go-gcc.cc	(revision 239179)
+++ gcc/go/go-gcc.cc	(working copy)
@@ -953,6 +953,14 @@  Gcc_backend::function_type(const Btyped_
   if (result == error_mark_node)
     return this->error_type();
 
+  // The libffi library can not represent a zero-sized object.  To
+  // avoid causing confusion on 32-bit SPARC, we treat a function that
+  // returns a zero-sized value as returning void.  That should do no
+  // harm since there is no actual value to be returned.  See
+  // https://gcc.gnu.org/PR72814 for details.
+  if (result != void_type_node && int_size_in_bytes(result) == 0)
+    result = void_type_node;
+
   tree fntype = build_function_type(result, args);
   if (fntype == error_mark_node)
     return this->error_type();
@@ -2127,6 +2135,27 @@  Gcc_backend::return_statement(Bfunction*
   if (result == error_mark_node)
     return this->error_statement();
 
+  // If the result size is zero bytes, we have set the function type
+  // to have a result type of void, so don't return anything.
+  // See the function_type method.
+  if (int_size_in_bytes(TREE_TYPE(result)) == 0)
+    {
+      tree stmt_list = NULL_TREE;
+      for (std::vector<Bexpression*>::const_iterator p = vals.begin();
+	   p != vals.end();
+	   p++)
+	{
+	  tree val = (*p)->get_tree();
+	  if (val == error_mark_node)
+	    return this->error_statement();
+	  append_to_statement_list(val, &stmt_list);
+	}
+      tree ret = fold_build1_loc(location.gcc_location(), RETURN_EXPR,
+				 void_type_node, NULL_TREE);
+      append_to_statement_list(ret, &stmt_list);
+      return this->make_statement(stmt_list);
+    }
+
   tree ret;
   if (vals.empty())
     ret = fold_build1_loc(location.gcc_location(), RETURN_EXPR, void_type_node,
Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 239225)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -1,4 +1,4 @@ 
-eeeeff3e3dd6c09aaefdf13cce99a5beff47a095
+5e4c16d4fea39835e16f17c3d2b2e85f5c81d815
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: libgo/runtime/go-ffi.c
===================================================================
--- libgo/runtime/go-ffi.c	(revision 238653)
+++ libgo/runtime/go-ffi.c	(working copy)
@@ -288,6 +288,17 @@  go_func_return_ffi (const struct __go_fu
 
   types = (const struct __go_type_descriptor **) func->__out.__values;
 
+  // We compile a function that returns a zero-sized value as though
+  // it returns void.  This works around a problem in libffi: it can't
+  // represent a zero-sized value.
+  for (i = 0; i < count; ++i)
+    {
+      if (types[i]->__size > 0)
+	break;
+    }
+  if (i == count)
+    return &ffi_type_void;
+
   if (count == 1)
     return go_type_to_ffi (types[0]);