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 <[email protected]>
* 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)
+ }
+}