reflect: fix variadic arg for funcs created by MakeFunc.
Short circuit for calling values funcs by MakeFunc was placed
before variadic arg rearrangement code in reflect.call.
Fixes #7534.
LGTM=khr
R=golang-codereviews, bradfitz, khr, rsc
CC=golang-codereviews
https://golang.org/cl/75370043
diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go
index c81f525..1e6341b 100644
--- a/src/pkg/reflect/all_test.go
+++ b/src/pkg/reflect/all_test.go
@@ -1512,6 +1512,23 @@
}
}
+func TestMakeFuncVariadic(t *testing.T) {
+ // Test that variadic arguments are packed into a slice and passed as last arg
+ fn := func(_ int, is ...int) []int { return nil }
+ fv := MakeFunc(TypeOf(fn), func(in []Value) []Value { return in[1:2] })
+ ValueOf(&fn).Elem().Set(fv)
+
+ r := fv.Call([]Value{ValueOf(1), ValueOf(2), ValueOf(3)})[0].Interface().([]int)
+ if r[0] != 2 || r[1] != 3 {
+ t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
+ }
+
+ r = fv.CallSlice([]Value{ValueOf(1), ValueOf([]int{2, 3})})[0].Interface().([]int)
+ if r[0] != 2 || r[1] != 3 {
+ t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
+ }
+}
+
type Point struct {
x, y int
}
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go
index a14b3a2..720090b 100644
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -453,17 +453,6 @@
panic("reflect.Value.Call: call of nil function")
}
- // If target is makeFuncStub, short circuit the unpack onto stack /
- // pack back into []Value for the args and return values. Just do the
- // call directly.
- // We need to do this here because otherwise we have a situation where
- // reflect.callXX calls makeFuncStub, neither of which knows the
- // layout of the args. That's bad for precise gc & stack copying.
- x := (*makeFuncImpl)(fn)
- if x.code == makeFuncStubCode {
- return x.fn(in)
- }
-
isSlice := op == "CallSlice"
n := t.NumIn()
if isSlice {
@@ -521,6 +510,17 @@
}
nout := t.NumOut()
+ // If target is makeFuncStub, short circuit the unpack onto stack /
+ // pack back into []Value for the args and return values. Just do the
+ // call directly.
+ // We need to do this here because otherwise we have a situation where
+ // reflect.callXX calls makeFuncStub, neither of which knows the
+ // layout of the args. That's bad for precise gc & stack copying.
+ x := (*makeFuncImpl)(fn)
+ if x.code == makeFuncStubCode {
+ return x.fn(in)
+ }
+
// If the target is methodValueCall, do its work here: add the receiver
// argument and call the real target directly.
// We need to do this here because otherwise we have a situation where