]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.regabi] cmd/compile: fix defined-pointer method call check
authorMatthew Dempsky <mdempsky@google.com>
Sat, 26 Dec 2020 09:06:03 +0000 (01:06 -0800)
committerMatthew Dempsky <mdempsky@google.com>
Wed, 30 Dec 2020 04:38:20 +0000 (04:38 +0000)
The compiler has logic to check whether we implicitly dereferenced a
defined pointer while trying to select a method. However, rather than
checking whether there were any implicit dereferences of a defined
pointer, it was finding the innermost dereference/selector expression
and checking whether that was dereferencing a named pointer. Moreover,
it was only checking defined pointer declared in the package block.

This CL restructures the code to match go/types and gccgo's behavior.

Fixes #43384.

Change-Id: I7bddfe2515776d9480eb2c7286023d4c15423888
Reviewed-on: https://go-review.googlesource.com/c/go/+/280392
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
Trust: Robert Griesemer <gri@golang.org>
Trust: Matthew Dempsky <mdempsky@google.com>

src/cmd/compile/internal/typecheck/typecheck.go
test/fixedbugs/issue43384.go [new file with mode: 0644]

index ebdcc4a72e7d0e784dbcd6c93ecc0507f8ca2027..b79739bfeba3295f7be4e928c317a541a2b35f3b 100644 (file)
@@ -1328,6 +1328,7 @@ func lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field {
                        // Already in the process of diagnosing an error.
                        return f2
                }
+               orig := n.X
                tt := n.X.Type()
                types.CalcSize(tt)
                rcvr := f2.Type.Recv().Type
@@ -1358,20 +1359,28 @@ func lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field {
                        }
                }
 
-               implicit, ll := n.Implicit(), n.X
-               for ll != nil && (ll.Op() == ir.ODOT || ll.Op() == ir.ODOTPTR || ll.Op() == ir.ODEREF) {
-                       switch l := ll.(type) {
+               // Check that we haven't implicitly dereferenced any defined pointer types.
+               for x := n.X; ; {
+                       var inner ir.Node
+                       implicit := false
+                       switch x := x.(type) {
+                       case *ir.AddrExpr:
+                               inner, implicit = x.X, x.Implicit()
                        case *ir.SelectorExpr:
-                               implicit, ll = l.Implicit(), l.X
+                               inner, implicit = x.X, x.Implicit()
                        case *ir.StarExpr:
-                               implicit, ll = l.Implicit(), l.X
+                               inner, implicit = x.X, x.Implicit()
                        }
-               }
-               if implicit && ll.Type().IsPtr() && ll.Type().Sym() != nil && ll.Type().Sym().Def != nil && ir.AsNode(ll.Type().Sym().Def).Op() == ir.OTYPE {
-                       // It is invalid to automatically dereference a named pointer type when selecting a method.
-                       // Make n.Left == ll to clarify error message.
-                       n.X = ll
-                       return nil
+                       if !implicit {
+                               break
+                       }
+                       if inner.Type().Sym() != nil && (x.Op() == ir.ODEREF || x.Op() == ir.ODOTPTR) {
+                               // Found an implicit dereference of a defined pointer type.
+                               // Restore n.X for better error message.
+                               n.X = orig
+                               return nil
+                       }
+                       x = inner
                }
 
                n.Selection = f2
diff --git a/test/fixedbugs/issue43384.go b/test/fixedbugs/issue43384.go
new file mode 100644 (file)
index 0000000..1bd793b
--- /dev/null
@@ -0,0 +1,124 @@
+// errorcheck
+
+// Copyright 2020 The Go Authors. All rights reserved.  Use of this
+// source code is governed by a BSD-style license that can be found in
+// the LICENSE file.
+
+package p
+
+type T int
+
+func (T) Mv()  {}
+func (*T) Mp() {}
+
+type P1 struct{ T }
+type P2 struct{ *T }
+type P3 *struct{ T }
+type P4 *struct{ *T }
+
+func _() {
+       {
+               var p P1
+               p.Mv()
+               (&p).Mv()
+               (*&p).Mv()
+               p.Mp()
+               (&p).Mp()
+               (*&p).Mp()
+       }
+       {
+               var p P2
+               p.Mv()
+               (&p).Mv()
+               (*&p).Mv()
+               p.Mp()
+               (&p).Mp()
+               (*&p).Mp()
+       }
+       {
+               var p P3
+               p.Mv()     // ERROR "undefined"
+               (&p).Mv()  // ERROR "undefined"
+               (*&p).Mv() // ERROR "undefined"
+               (**&p).Mv()
+               (*p).Mv()
+               (&*p).Mv()
+               p.Mp()     // ERROR "undefined"
+               (&p).Mp()  // ERROR "undefined"
+               (*&p).Mp() // ERROR "undefined"
+               (**&p).Mp()
+               (*p).Mp()
+               (&*p).Mp()
+       }
+       {
+               var p P4
+               p.Mv()     // ERROR "undefined"
+               (&p).Mv()  // ERROR "undefined"
+               (*&p).Mv() // ERROR "undefined"
+               (**&p).Mv()
+               (*p).Mv()
+               (&*p).Mv()
+               p.Mp()     // ERROR "undefined"
+               (&p).Mp()  // ERROR "undefined"
+               (*&p).Mp() // ERROR "undefined"
+               (**&p).Mp()
+               (*p).Mp()
+               (&*p).Mp()
+       }
+}
+
+func _() {
+       type P5 struct{ T }
+       type P6 struct{ *T }
+       type P7 *struct{ T }
+       type P8 *struct{ *T }
+
+       {
+               var p P5
+               p.Mv()
+               (&p).Mv()
+               (*&p).Mv()
+               p.Mp()
+               (&p).Mp()
+               (*&p).Mp()
+       }
+       {
+               var p P6
+               p.Mv()
+               (&p).Mv()
+               (*&p).Mv()
+               p.Mp()
+               (&p).Mp()
+               (*&p).Mp()
+       }
+       {
+               var p P7
+               p.Mv()     // ERROR "undefined"
+               (&p).Mv()  // ERROR "undefined"
+               (*&p).Mv() // ERROR "undefined"
+               (**&p).Mv()
+               (*p).Mv()
+               (&*p).Mv()
+               p.Mp()     // ERROR "undefined"
+               (&p).Mp()  // ERROR "undefined"
+               (*&p).Mp() // ERROR "undefined"
+               (**&p).Mp()
+               (*p).Mp()
+               (&*p).Mp()
+       }
+       {
+               var p P8
+               p.Mv()     // ERROR "undefined"
+               (&p).Mv()  // ERROR "undefined"
+               (*&p).Mv() // ERROR "undefined"
+               (**&p).Mv()
+               (*p).Mv()
+               (&*p).Mv()
+               p.Mp()     // ERROR "undefined"
+               (&p).Mp()  // ERROR "undefined"
+               (*&p).Mp() // ERROR "undefined"
+               (**&p).Mp()
+               (*p).Mp()
+               (&*p).Mp()
+       }
+}