This patch to the Go frontend changes value methods to always check
that the pointer they are passed is not nil.  We already dereference
the pointer to copy the value, but if the method does not use the
value then the pointer dereference may be optimized away.  Do an
explicit nil check so that we get the panic that is required by the
language.  This fixes https://golang.org/issue/19806.  I added a test
case to gcc/testsuite/go.go-torture/execute to test this at various
optimization levels; the test used to fail at -O1 and above.
Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.  Committed
to mainline.

Ian

2018-01-31  Ian Lance Taylor  <i...@golang.org>

* go.go-torture/execute/printnil.go: New test.
Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE     (revision 257250)
+++ gcc/go/gofrontend/MERGE     (working copy)
@@ -1,4 +1,4 @@
-65eaa9003db4effc9c5ffe9c955e9534ba5d7d15
+71758f9ca1804743afe178f0e2fca489e0217474
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: gcc/go/gofrontend/gogo.cc
===================================================================
--- gcc/go/gofrontend/gogo.cc   (revision 257250)
+++ gcc/go/gofrontend/gogo.cc   (working copy)
@@ -5610,7 +5610,7 @@ Function::build(Gogo* gogo, Named_object
                   Expression::make_var_reference(parm_no, loc);
               parm_ref =
                   Expression::make_dereference(parm_ref,
-                                               Expression::NIL_CHECK_DEFAULT,
+                                               Expression::NIL_CHECK_NEEDED,
                                                loc);
              if ((*p)->var_value()->is_in_heap())
                parm_ref = Expression::make_heap_expression(parm_ref, loc);
Index: gcc/testsuite/go.go-torture/execute/printnil.go
===================================================================
--- gcc/testsuite/go.go-torture/execute/printnil.go     (nonexistent)
+++ gcc/testsuite/go.go-torture/execute/printnil.go     (working copy)
@@ -0,0 +1,19 @@
+// printnil checks that fmt correctly handles a nil pointer receiver
+// for a value method at all optimization levels.
+package main
+
+import "fmt"
+
+type MyType struct {
+       val int
+}
+
+func (t MyType) String() string {
+       return "foobar"
+}
+
+func main() {
+       if got := fmt.Sprintf("%s", (*MyType)(nil)); got != "<nil>" {
+               panic(got)
+       }
+}

Reply via email to