diff mbox

[gccgo] Fix for type assertions

Message ID mcraanrg38a.fsf@google.com
State New
Headers show

Commit Message

Ian Lance Taylor Sept. 9, 2010, 12:39 a.m. UTC
This gccgo patch does three things.  It fixes type assertions for global
variables, by not creating an unnecessary temporary variable.  It fixes
the unsafe.Pointer checks for type assertions, by only permitting a
conversion to uintptr.  It gives an error for impossible type assertions
that can never be satisfied.  Committed to gccgo  branch.

Ian
diff mbox

Patch

diff -r 1c23caeb2ccd go/expressions.cc
--- a/go/expressions.cc	Wed Sep 08 16:24:55 2010 -0700
+++ b/go/expressions.cc	Wed Sep 08 17:35:24 2010 -0700
@@ -704,25 +704,16 @@ 
   tree val = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field,
 		    NULL_TREE);
 
-  // If the value is a pointer, then we can just get it from the
-  // interface.  Otherwise we have to make a copy.
-  if (lhs_type->points_to() != NULL)
-    return build2(COMPOUND_EXPR, lhs_type_tree, call,
-		  fold_convert_loc(location, lhs_type_tree, val));
-
-  tree tmp = create_tmp_var(lhs_type_tree, NULL);
-  DECL_IGNORED_P(tmp) = 0;
-
-  tree make_tmp = fold_build1_loc(location, DECL_EXPR, void_type_node, tmp);
-  tree s = build2(COMPOUND_EXPR, void_type_node, call, make_tmp);
-
-  val = fold_convert_loc(location, build_pointer_type(lhs_type_tree), val);
-  val = build_fold_indirect_ref_loc(location, val);
-  tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node,
-			     tmp, val);
-  s = build2(COMPOUND_EXPR, void_type_node, s, set);
-
-  return build2(COMPOUND_EXPR, lhs_type_tree, s, tmp);
+  // If the value is a pointer, then it is the value we want.
+  // Otherwise it points to the value.
+  if (lhs_type->points_to() == NULL)
+    {
+      val = fold_convert_loc(location, build_pointer_type(lhs_type_tree), val);
+      val = build_fold_indirect_ref_loc(location, val);
+    }
+
+  return build2(COMPOUND_EXPR, lhs_type_tree, call,
+		fold_convert_loc(location, lhs_type_tree, val));
 }
 
 // Convert an expression to a tree.  This is implemented by the child
@@ -11459,18 +11450,40 @@ 
   if (expr_type->is_unsafe_pointer_type())
     {
       if (this->type_->points_to() == NULL
-	  && this->type_->integer_type() == NULL)
-	this->report_error(_("invalid unsafe.pointer conversion"));
+	  && (this->type_->integer_type() == NULL
+	      || (this->type_->forwarded()
+		  != Type::lookup_integer_type("uintptr"))))
+	this->report_error(_("invalid unsafe.Pointer conversion"));
     }
   else if (this->type_->is_unsafe_pointer_type())
     {
-      if (expr_type->interface_type() == NULL
-	  && expr_type->points_to() == NULL
-	  && expr_type->integer_type() == NULL)
-	this->report_error(_("invalid unsafe.pointer conversion"));
+      if (expr_type->points_to() == NULL
+	  && (expr_type->integer_type() == NULL
+	      || (expr_type->forwarded()
+		  != Type::lookup_integer_type("uintptr"))))
+	this->report_error(_("invalid unsafe.Pointer conversion"));
     }
   else if (expr_type->interface_type() == NULL)
-    this->report_error(_("type guard only valid for interface types"));
+    this->report_error(_("type assertion only valid for interface types"));
+  else if (this->type_->interface_type() == NULL)
+    {
+      std::string reason;
+      if (!expr_type->interface_type()->implements_interface(this->type_,
+							     &reason))
+	{
+	  if (reason.empty())
+	    this->report_error(_("impossible type assertion: "
+				 "type does not implement interface"));
+	  else
+	    {
+	      error_at(this->location(),
+		       ("impossible type assertion: "
+			"type does not implement interface (%s)"),
+		       reason.c_str());
+	      this->set_is_error();
+	    }
+	}
+    }
 }
 
 // Return a tree for a type guard expression.