From 772d22885bec8e38816b41b9ec6befac77e5a671 Mon Sep 17 00:00:00 2001 From: Carl Chatfield Date: Tue, 8 Apr 2014 22:35:23 -0400 Subject: [PATCH] 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 --- src/pkg/reflect/all_test.go | 17 +++++++++++++++++ src/pkg/reflect/value.go | 22 +++++++++++----------- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go index c81f525094..1e6341bd0b 100644 --- a/src/pkg/reflect/all_test.go +++ b/src/pkg/reflect/all_test.go @@ -1512,6 +1512,23 @@ func TestMakeFuncInterface(t *testing.T) { } } +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 a14b3a2f80..720090bd66 100644 --- a/src/pkg/reflect/value.go +++ b/src/pkg/reflect/value.go @@ -453,17 +453,6 @@ func (v Value) call(op string, in []Value) []Value { 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 @@ func (v Value) call(op string, in []Value) []Value { } 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 -- 2.50.0