mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
cmd/link: treat reflect.Value.Method like Call
Fixes #14740 Change-Id: Iad8d971c21977b0a1f4ef55a08bb180a8125e976 Reviewed-on: https://go-review.googlesource.com/20562 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: David Crawshaw <crawshaw@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
5aa5db7593
commit
e2836935bb
@ -25,7 +25,7 @@ import (
|
|||||||
//
|
//
|
||||||
// 1. direct call
|
// 1. direct call
|
||||||
// 2. through a reachable interface type
|
// 2. through a reachable interface type
|
||||||
// 3. reflect.Value.Call / reflect.Method.Func
|
// 3. reflect.Value.Call, .Method, or reflect.Method.Func
|
||||||
//
|
//
|
||||||
// The first case is handled by the flood fill, a directly called method
|
// The first case is handled by the flood fill, a directly called method
|
||||||
// is marked as reachable.
|
// is marked as reachable.
|
||||||
@ -35,11 +35,12 @@ import (
|
|||||||
// against the interface method signatures, if it matches it is marked
|
// against the interface method signatures, if it matches it is marked
|
||||||
// as reachable. This is extremely conservative, but easy and correct.
|
// as reachable. This is extremely conservative, but easy and correct.
|
||||||
//
|
//
|
||||||
// The third case is handled by looking to see if reflect.Value.Call is
|
// The third case is handled by looking to see if any of:
|
||||||
// ever marked reachable, or if a reflect.Method struct is ever
|
// - reflect.Value.Call is reachable
|
||||||
// constructed by a call to reflect.Type.Method or MethodByName. If it
|
// - reflect.Value.Method is reachable
|
||||||
// is, all bets are off and all exported methods of reachable types are
|
// - reflect.Type.Method or MethodByName is called.
|
||||||
// marked reachable.
|
// If any of these happen, all bets are off and all exported methods
|
||||||
|
// of reachable types are marked reachable.
|
||||||
//
|
//
|
||||||
// Any unreached text symbols are removed from ctxt.Textp.
|
// Any unreached text symbols are removed from ctxt.Textp.
|
||||||
func deadcode(ctxt *Link) {
|
func deadcode(ctxt *Link) {
|
||||||
@ -58,14 +59,17 @@ func deadcode(ctxt *Link) {
|
|||||||
d.flood()
|
d.flood()
|
||||||
|
|
||||||
callSym := Linkrlookup(ctxt, "reflect.Value.Call", 0)
|
callSym := Linkrlookup(ctxt, "reflect.Value.Call", 0)
|
||||||
callSymSeen := false
|
methSym := Linkrlookup(ctxt, "reflect.Value.Method", 0)
|
||||||
|
reflectSeen := false
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if callSym != nil && (callSym.Attr.Reachable() || d.reflectMethod) {
|
if !reflectSeen {
|
||||||
// Methods are called via reflection. Give up on
|
if d.reflectMethod || (callSym != nil && callSym.Attr.Reachable()) || (methSym != nil && methSym.Attr.Reachable()) {
|
||||||
// static analysis, mark all exported methods of
|
// Methods might be called via reflection. Give up on
|
||||||
// all reachable types as reachable.
|
// static analysis, mark all exported methods of
|
||||||
callSymSeen = true
|
// all reachable types as reachable.
|
||||||
|
reflectSeen = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark all methods that could satisfy a discovered
|
// Mark all methods that could satisfy a discovered
|
||||||
@ -74,7 +78,7 @@ func deadcode(ctxt *Link) {
|
|||||||
// in the last pass.
|
// in the last pass.
|
||||||
var rem []methodref
|
var rem []methodref
|
||||||
for _, m := range d.markableMethods {
|
for _, m := range d.markableMethods {
|
||||||
if (callSymSeen && m.isExported()) || d.ifaceMethod[m.m] {
|
if (reflectSeen && m.isExported()) || d.ifaceMethod[m.m] {
|
||||||
d.markMethod(m)
|
d.markMethod(m)
|
||||||
} else {
|
} else {
|
||||||
rem = append(rem, m)
|
rem = append(rem, m)
|
||||||
|
30
test/reflectmethod4.go
Normal file
30
test/reflectmethod4.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// run
|
||||||
|
|
||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
// The linker can prune methods that are not directly called or
|
||||||
|
// assigned to interfaces, but only if reflect.Value.Method is
|
||||||
|
// never used. Test it here.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
var called = false
|
||||||
|
|
||||||
|
type M int
|
||||||
|
|
||||||
|
func (m M) UniqueMethodName() {
|
||||||
|
called = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var v M
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
reflect.ValueOf(v).Method(0).Interface().(func())()
|
||||||
|
if !called {
|
||||||
|
panic("UniqueMethodName not called")
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user