]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.regabi] cmd/compile: stop mangling SelectorExpr.Sel for ODOTMETH
authorMatthew Dempsky <mdempsky@google.com>
Sun, 27 Dec 2020 02:56:36 +0000 (18:56 -0800)
committerMatthew Dempsky <mdempsky@google.com>
Mon, 28 Dec 2020 07:44:07 +0000 (07:44 +0000)
ODOTMETH is unique among SelectorExpr expressions, in that Sel gets
mangled so that it no longer has the original identifier that was
selected (e.g., just "Foo"), but instead the qualified symbol name for
the selected method (e.g., "pkg.Type.Foo"). This is rarely useful, and
instead results in a lot of compiler code needing to worry about
undoing this change.

This CL changes ODOTMETH to leave the original symbol in place. The
handful of code locations where the mangled symbol name is actually
wanted are updated to use ir.MethodExprName(n).Sym() or (equivalently)
ir.MethodExprName(n).Func.Sym() instead.

Historically, the compiler backend has mistakenly used types.Syms
where it should have used ir.Name/ir.Funcs. And this change in
particular may risk breaking something, as the SelectorExpr.Sel will
no longer point at a symbol that uniquely identifies the called
method. However, I expect CL 280294 (desugar OCALLMETH into OCALLFUNC)
to have substantially reduced this risk, as ODOTMETH expressions are
now replaced entirely earlier in the compiler.

Passes toolstash -cmp.

Change-Id: If3c9c3b7df78ea969f135840574cf89e1d263876
Reviewed-on: https://go-review.googlesource.com/c/go/+/280436
Trust: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
src/cmd/compile/internal/inline/inl.go
src/cmd/compile/internal/ir/fmt.go
src/cmd/compile/internal/typecheck/expr.go
src/cmd/compile/internal/typecheck/func.go
src/cmd/compile/internal/typecheck/iexport.go
src/cmd/compile/internal/typecheck/typecheck.go
src/cmd/compile/internal/types/fmt.go
test/fixedbugs/issue31053.dir/main.go

index 9ffb08048a6f6806d3ac3f8db908adfc9ce4c5e6..67162771e93508fd7ea0089f6007373927f694a0 100644 (file)
@@ -324,19 +324,17 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
                if t == nil {
                        base.Fatalf("no function type for [%p] %+v\n", n.X, n.X)
                }
-               if types.IsRuntimePkg(n.X.Sym().Pkg) {
-                       fn := n.X.Sym().Name
-                       if fn == "heapBits.nextArena" {
-                               // Special case: explicitly allow
-                               // mid-stack inlining of
-                               // runtime.heapBits.next even though
-                               // it calls slow-path
-                               // runtime.heapBits.nextArena.
-                               break
-                       }
+               fn := ir.MethodExprName(n.X).Func
+               if types.IsRuntimePkg(fn.Sym().Pkg) && fn.Sym().Name == "heapBits.nextArena" {
+                       // Special case: explicitly allow
+                       // mid-stack inlining of
+                       // runtime.heapBits.next even though
+                       // it calls slow-path
+                       // runtime.heapBits.nextArena.
+                       break
                }
-               if inlfn := ir.MethodExprName(n.X).Func; inlfn.Inl != nil {
-                       v.budget -= inlfn.Inl.Cost
+               if fn.Inl != nil {
+                       v.budget -= fn.Inl.Cost
                        break
                }
                // Call cost for non-leaf inlining.
@@ -531,7 +529,7 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.No
                // Prevent inlining some reflect.Value methods when using checkptr,
                // even when package reflect was compiled without it (#35073).
                n := n.(*ir.CallExpr)
-               if s := n.X.Sym(); base.Debug.Checkptr != 0 && types.IsReflectPkg(s.Pkg) && (s.Name == "Value.UnsafeAddr" || s.Name == "Value.Pointer") {
+               if s := ir.MethodExprName(n.X).Sym(); base.Debug.Checkptr != 0 && types.IsReflectPkg(s.Pkg) && (s.Name == "Value.UnsafeAddr" || s.Name == "Value.Pointer") {
                        return n
                }
        }
index 2b73c5ac1bb4acf12090d6da54025c5a9dd3b502..f52c639c517fa9f78ac2d680d30f264c35fedbaf 100644 (file)
@@ -756,7 +756,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
                        fmt.Fprint(s, ".<nil>")
                        return
                }
-               fmt.Fprintf(s, ".%s", types.SymMethodName(n.Method.Sym))
+               fmt.Fprintf(s, ".%s", n.Method.Sym.Name)
 
        case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
                n := n.(*SelectorExpr)
@@ -765,7 +765,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
                        fmt.Fprint(s, ".<nil>")
                        return
                }
-               fmt.Fprintf(s, ".%s", types.SymMethodName(n.Sel))
+               fmt.Fprintf(s, ".%s", n.Sel.Name)
 
        case ODOTTYPE, ODOTTYPE2:
                n := n.(*TypeAssertExpr)
index 879ae385c7b438ae5eade05ee6aaa5f1a8e52565..3e7a880c2a466a2e032b2c70425afd980ee82b1a 100644 (file)
@@ -571,7 +571,6 @@ func tcDot(n *ir.SelectorExpr, top int) ir.Node {
        }
 
        n.X = typecheck(n.X, ctxExpr|ctxType)
-
        n.X = DefaultLit(n.X, nil)
 
        t := n.X.Type()
@@ -581,8 +580,6 @@ func tcDot(n *ir.SelectorExpr, top int) ir.Node {
                return n
        }
 
-       s := n.Sel
-
        if n.X.Op() == ir.OTYPE {
                return typecheckMethodExpr(n)
        }
@@ -629,7 +626,10 @@ func tcDot(n *ir.SelectorExpr, top int) ir.Node {
        }
 
        if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && top&ctxCallee == 0 {
-               return tcCallPart(n, s)
+               // Create top-level function.
+               fn := makepartialcall(n)
+
+               return ir.NewCallPartExpr(n.Pos(), n.X, n.Selection, fn)
        }
        return n
 }
index fdac719ad9bbca2a4dfbbcd329643f98d51ce7f2..50f514a6db0a64c84c19c2943fc444cfebb524fb 100644 (file)
@@ -249,7 +249,9 @@ var globClosgen int32
 
 // makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
 // for partial calls.
-func makepartialcall(dot *ir.SelectorExpr, t0 *types.Type, meth *types.Sym) *ir.Func {
+func makepartialcall(dot *ir.SelectorExpr) *ir.Func {
+       t0 := dot.Type()
+       meth := dot.Sel
        rcvrtype := dot.X.Type()
        sym := ir.MethodSymSuffix(rcvrtype, meth, "-fm")
 
@@ -263,11 +265,10 @@ func makepartialcall(dot *ir.SelectorExpr, t0 *types.Type, meth *types.Sym) *ir.
        ir.CurFunc = nil
 
        // Set line number equal to the line number where the method is declared.
-       var m *types.Field
-       if lookdot0(meth, rcvrtype, &m, false) == 1 && m.Pos.IsKnown() {
-               base.Pos = m.Pos
+       if pos := dot.Selection.Pos; pos.IsKnown() {
+               base.Pos = pos
        }
-       // Note: !m.Pos.IsKnown() happens for method expressions where
+       // Note: !dot.Selection.Pos.IsKnown() happens for method expressions where
        // the method is implicitly declared. The Error method of the
        // built-in error type is one such method.  We leave the line
        // number at the use of the method expression in this
@@ -280,6 +281,7 @@ func makepartialcall(dot *ir.SelectorExpr, t0 *types.Type, meth *types.Sym) *ir.
        fn := DeclFunc(sym, tfn)
        fn.SetDupok(true)
        fn.SetNeedctxt(true)
+       fn.SetWrapper(true)
 
        // Declare and initialize variable holding receiver.
        cr := ir.NewClosureRead(rcvrtype, types.Rnd(int64(types.PtrSize), int64(rcvrtype.Align)))
@@ -382,23 +384,6 @@ func tcClosure(clo *ir.ClosureExpr, top int) {
        Target.Decls = append(Target.Decls, fn)
 }
 
-func tcCallPart(n ir.Node, sym *types.Sym) *ir.CallPartExpr {
-       switch n.Op() {
-       case ir.ODOTINTER, ir.ODOTMETH:
-               break
-
-       default:
-               base.Fatalf("invalid typecheckpartialcall")
-       }
-       dot := n.(*ir.SelectorExpr)
-
-       // Create top-level function.
-       fn := makepartialcall(dot, dot.Type(), sym)
-       fn.SetWrapper(true)
-
-       return ir.NewCallPartExpr(dot.Pos(), dot.X, dot.Selection, fn)
-}
-
 // type check function definition
 // To be called by typecheck, not directly.
 // (Call typecheckFunc instead.)
index 449d99266d365457710535483d1ef6d4e5494f5b..0c813a71ef41a160e8159137f664f283a469caa1 100644 (file)
@@ -594,23 +594,15 @@ func (w *exportWriter) selector(s *types.Sym) {
                base.Fatalf("missing currPkg")
        }
 
-       // Method selectors are rewritten into method symbols (of the
-       // form T.M) during typechecking, but we want to write out
-       // just the bare method name.
-       name := s.Name
-       if i := strings.LastIndex(name, "."); i >= 0 {
-               name = name[i+1:]
-       } else {
-               pkg := w.currPkg
-               if types.IsExported(name) {
-                       pkg = types.LocalPkg
-               }
-               if s.Pkg != pkg {
-                       base.Fatalf("package mismatch in selector: %v in package %q, but want %q", s, s.Pkg.Path, pkg.Path)
-               }
+       pkg := w.currPkg
+       if types.IsExported(s.Name) {
+               pkg = types.LocalPkg
+       }
+       if s.Pkg != pkg {
+               base.Fatalf("package mismatch in selector: %v in package %q, but want %q", s, s.Pkg.Path, pkg.Path)
        }
 
-       w.string(name)
+       w.string(s.Name)
 }
 
 func (w *exportWriter) typ(t *types.Type) {
index 1d070507fadad509eb2ba58b8a3519444953f470..b779f9ceb0f1403bbca22700f8742e624c21f610 100644 (file)
@@ -1297,7 +1297,6 @@ func lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field {
                        return nil
                }
 
-               n.Sel = ir.MethodSym(n.X.Type(), f2.Sym)
                n.Selection = f2
                n.SetType(f2.Type)
                n.SetOp(ir.ODOTMETH)
index bf37f01922a435afefbf1494f5d398bc3e295f65..cd0679f6b9efa5a62b4edcbf6d70be35504d75fb 100644 (file)
@@ -180,15 +180,6 @@ func symfmt(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) {
        b.WriteString(s.Name)
 }
 
-func SymMethodName(s *Sym) string {
-       // Skip leading "type." in method name
-       name := s.Name
-       if i := strings.LastIndex(name, "."); i >= 0 {
-               name = name[i+1:]
-       }
-       return name
-}
-
 // Type
 
 var BasicTypeNames = []string{
@@ -595,7 +586,10 @@ func fldconv(b *bytes.Buffer, f *Field, verb rune, mode fmtMode, visited map[*Ty
                        if funarg != FunargNone {
                                name = fmt.Sprint(f.Nname)
                        } else if verb == 'L' {
-                               name = SymMethodName(s)
+                               name = s.Name
+                               if name == ".F" {
+                                       name = "F" // Hack for toolstash -cmp.
+                               }
                                if !IsExported(name) && mode != fmtTypeIDName {
                                        name = sconv(s, 0, mode) // qualify non-exported names (used on structs, not on funarg)
                                }
index 895c262164ca43ebd3f329ab798595598b243c76..3bc75d17d2d80b660d00fda696a2516333478bc8 100644 (file)
@@ -35,8 +35,8 @@ func main() {
        _ = f.Exported
        _ = f.exported    // ERROR "f.exported undefined .type f1.Foo has no field or method exported, but does have Exported."
        _ = f.Unexported  // ERROR "f.Unexported undefined .type f1.Foo has no field or method Unexported."
-       _ = f.unexported  // ERROR "f.unexported undefined .cannot refer to unexported field or method f1..\*Foo..unexported."
-       f.unexported = 10 // ERROR "f.unexported undefined .cannot refer to unexported field or method f1..\*Foo..unexported."
-       f.unexported()    // ERROR "f.unexported undefined .cannot refer to unexported field or method f1..\*Foo..unexported."
+       _ = f.unexported  // ERROR "f.unexported undefined .cannot refer to unexported field or method unexported."
+       f.unexported = 10 // ERROR "f.unexported undefined .cannot refer to unexported field or method unexported."
+       f.unexported()    // ERROR "f.unexported undefined .cannot refer to unexported field or method unexported."
        _ = f.hook        // ERROR "f.hook undefined .cannot refer to unexported field or method hook."
 }