diff mbox

Go patch committed: Be more careful to follow type rules

Message ID mcrhaxynptk.fsf@dhcp-172-18-216-180.mtv.corp.google.com
State New
Headers show

Commit Message

Ian Lance Taylor March 9, 2012, 8:25 a.m. UTC
The Go frontend can create multiple instances of unnamed types that are,
in the Go language, the same type.  This can lead to using different
tree types when generating GENERIC.  This normally does no harm because
the differences are usually pointer types.  However, it is possible in
some cases to build two unnamed structs that are really the same type in
Go, but GENERIC does not permit assignments between different structs.
This patch makes the Go frontend stricter about this sort of thing, by
calling fold_convert or inserting a VIEW_CONVERT_EXPR where necessary.
Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
Committed to mainline.

Ian


2012-03-09  Ian Lance Taylor  <iant@google.com>

	* go-gcc.cc (Gcc_backend::assignment_statement): Convert the rhs
	to the lhs type if necessary.
diff mbox

Patch

Index: gcc/go/go-gcc.cc
===================================================================
--- gcc/go/go-gcc.cc	(revision 185115)
+++ gcc/go/go-gcc.cc	(working copy)
@@ -918,6 +918,30 @@  Gcc_backend::assignment_statement(Bexpre
     return this->compound_statement(this->expression_statement(lhs),
 				    this->expression_statement(rhs));
 
+  // Sometimes the same unnamed Go type can be created multiple times
+  // and thus have multiple tree representations.  Make sure this does
+  // not confuse the middle-end.
+  if (TREE_TYPE(lhs_tree) != TREE_TYPE(rhs_tree))
+    {
+      tree lhs_type_tree = TREE_TYPE(lhs_tree);
+      gcc_assert(TREE_CODE(lhs_type_tree) == TREE_CODE(TREE_TYPE(rhs_tree)));
+      if (POINTER_TYPE_P(lhs_type_tree)
+	  || INTEGRAL_TYPE_P(lhs_type_tree)
+	  || SCALAR_FLOAT_TYPE_P(lhs_type_tree)
+	  || COMPLEX_FLOAT_TYPE_P(lhs_type_tree))
+	rhs_tree = fold_convert_loc(location.gcc_location(), lhs_type_tree,
+				    rhs_tree);
+      else if (TREE_CODE(lhs_type_tree) == RECORD_TYPE
+	       || TREE_CODE(lhs_type_tree) == ARRAY_TYPE)
+	{
+	  gcc_assert(int_size_in_bytes(lhs_type_tree)
+		     == int_size_in_bytes(TREE_TYPE(rhs_tree)));
+	  rhs_tree = fold_build1_loc(location.gcc_location(),
+				     VIEW_CONVERT_EXPR,
+				     lhs_type_tree, rhs_tree);
+	}
+    }
+
   return this->make_statement(fold_build2_loc(location.gcc_location(),
                                               MODIFY_EXPR,
 					      void_type_node,
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc	(revision 185092)
+++ gcc/go/gofrontend/expressions.cc	(working copy)
@@ -205,9 +205,6 @@  Expression::convert_for_assignment(Trans
 				   Type* rhs_type, tree rhs_tree,
 				   Location location)
 {
-  if (lhs_type == rhs_type)
-    return rhs_tree;
-
   if (lhs_type->is_error() || rhs_type->is_error())
     return error_mark_node;
 
@@ -220,7 +217,7 @@  Expression::convert_for_assignment(Trans
   if (lhs_type_tree == error_mark_node)
     return error_mark_node;
 
-  if (lhs_type->interface_type() != NULL)
+  if (lhs_type != rhs_type && lhs_type->interface_type() != NULL)
     {
       if (rhs_type->interface_type() == NULL)
 	return Expression::convert_type_to_interface(context, lhs_type,
@@ -231,7 +228,7 @@  Expression::convert_for_assignment(Trans
 							  rhs_type, rhs_tree,
 							  false, location);
     }
-  else if (rhs_type->interface_type() != NULL)
+  else if (lhs_type != rhs_type && rhs_type->interface_type() != NULL)
     return Expression::convert_interface_to_type(context, lhs_type, rhs_type,
 						 rhs_tree, location);
   else if (lhs_type->is_slice_type() && rhs_type->is_nil_type())
@@ -289,10 +286,16 @@  Expression::convert_for_assignment(Trans
 	   || (TREE_CODE(lhs_type_tree) == ARRAY_TYPE
 	       && TREE_CODE(TREE_TYPE(rhs_tree)) == ARRAY_TYPE))
     {
+      // Avoid confusion from zero sized variables which may be
+      // represented as non-zero-sized.
+      if (int_size_in_bytes(lhs_type_tree) == 0
+	  || int_size_in_bytes(TREE_TYPE(rhs_tree)) == 0)
+	return rhs_tree;
+
       // This conversion must be permitted by Go, or we wouldn't have
       // gotten here.
       go_assert(int_size_in_bytes(lhs_type_tree)
-		 == int_size_in_bytes(TREE_TYPE(rhs_tree)));
+		== int_size_in_bytes(TREE_TYPE(rhs_tree)));
       return fold_build1_loc(location.gcc_location(), VIEW_CONVERT_EXPR,
                              lhs_type_tree, rhs_tree);
     }