Skip to content

cmd/link: Unused interface methods don't get gc'd #42421

Closed
@rojer

Description

@rojer

Follow up to #38685 that seems to have solved a simple case but does not eliminate an unused interface method across packages

What version of Go are you using (go version)?

[rojer@nbd /tmp]$ GOROOT=/home/rojer/go/go-git /home/rojer/go/go-git/bin/go version
go version devel +b7e0adfee2 Fri Nov 6 07:55:52 2020 +0000 linux/amd64

Does this issue reproduce with the latest release?

yes

What operating system and processor architecture are you using (go env)?

go env Output
[rojer@nbd /tmp]$ GOROOT=/home/rojer/go/go-git /home/rojer/go/go-git/bin/go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/rojer/.cache/go-build"
GOENV="/home/rojer/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/rojer/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/rojer/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/home/rojer/go/go-git"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/home/rojer/go/go-git/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build351127229=/tmp/go-build -gno-record-gcc-switches"

What did you do?

source:

[rojer@nbd /tmp]$ find foobar/
foobar/
foobar/go.mod
foobar/foo
foobar/foo/foo.go
foobar/bar
foobar/bar/bar.go
[rojer@nbd /tmp]$ cat foobar/foo/foo.go
package main

import (
        "foobar/bar"
)

func main() {
        // Test unused method elimination.
        var b bar.Interface
        b = bar.Bar{}
        b.UsedInterfaceMethod()
}
[rojer@nbd /tmp]$ cat foobar/bar/bar.go 
package bar

import "fmt"

type Interface interface {
        UsedInterfaceMethod()
        UnusedInterfaceMethod()
}

type Bar struct{}

func (Bar) UsedInterfaceMethod() {
        fmt.Println("one")
}

// This method is unused but cannot be eliminated yet.
// https://github.com/golang/go/issues/38685
func (Bar) UnusedInterfaceMethod() {
        fmt.Println("two")
}

// This method is unused and should be eliminated.
func (Bar) UnusedNonInterfaceMethod() {
        fmt.Println("three")
}

What did you expect to see?

foobar/bar.(*Bar).UnusedInterfaceMethod should not make it into the final binary.
in fact, neither should foobar/bar.(*Bar).UsedInterfaceMethod because pointer variant is not used.

in other words, all that should be left from bar.Bar should be bar.Bar.UsedInterfaceMethod.

interesting, that foobar/bar.Bar.UnusedInterfaceMethod does get eliminated but not the bar.*Bar variant.
why is it even generated in the first place?

What did you see instead?

[rojer@nbd /tmp/foobar/foo]$ GOROOT=/home/rojer/go/go-git /home/rojer/go/go-git/bin/go build 
[rojer@nbd /tmp/foobar/foo]$ GOROOT=/home/rojer/go/go-git /home/rojer/go/go-git/bin/go tool nm -size foo | grep foobar/bar
  497080        187 T foobar/bar.(*Bar).UnusedInterfaceMethod
  497140        187 T foobar/bar.(*Bar).UsedInterfaceMethod
  535e20         32 D foobar/bar..inittask
  496fe0        138 T foobar/bar.Bar.UsedInterfaceMethod
  4da288         40 R go.itab.foobar/bar.Bar,foobar/bar.Interface

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsDecisionFeedback is required from experts, contributors, and/or the community before a change can be made.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions