Patchwork [gccgo] Fix for type assertions

login
register
mail settings
Submitter Ian Taylor
Date Sept. 9, 2010, 12:39 a.m.
Message ID <mcraanrg38a.fsf@google.com>
Download mbox | patch
Permalink /patch/64248/
State New
Headers show

Comments

Ian Taylor - Sept. 9, 2010, 12:39 a.m.
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

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.