diff --git a/compiler/defer.go b/compiler/defer.go index 4fd9715b5..e58002798 100644 --- a/compiler/defer.go +++ b/compiler/defer.go @@ -372,12 +372,12 @@ func (b *builder) createDefer(instr *ssa.Defer) { // Method call on an interface. // Get callback type number. - methodName := instr.Call.Method.FullName() - if _, ok := b.deferInvokeFuncs[methodName]; !ok { - b.deferInvokeFuncs[methodName] = len(b.allDeferFuncs) + key := b.getInvokeFunctionName(&instr.Call) + if _, ok := b.deferInvokeFuncs[key]; !ok { + b.deferInvokeFuncs[key] = len(b.allDeferFuncs) b.allDeferFuncs = append(b.allDeferFuncs, &instr.Call) } - callback := llvm.ConstInt(b.uintptrType, uint64(b.deferInvokeFuncs[methodName]), false) + callback := llvm.ConstInt(b.uintptrType, uint64(b.deferInvokeFuncs[key]), false) // Collect all values to be put in the struct (starting with // runtime._defer fields, followed by the call parameters). diff --git a/compiler/interface.go b/compiler/interface.go index bb427e6e5..c94f88175 100644 --- a/compiler/interface.go +++ b/compiler/interface.go @@ -1193,8 +1193,7 @@ func (c *compilerContext) getMethodSetValue(methods []*types.Func) llvm.Value { // thunk is declared, not defined: it will be defined by the interface lowering // pass. func (c *compilerContext) getInvokeFunction(instr *ssa.CallCommon) llvm.Value { - s, _ := c.getTypeCodeName(instr.Value.Type().Underlying()) - fnName := s + "." + instr.Method.Name() + "$invoke" + fnName := c.getInvokeFunctionName(instr) llvmFn := c.mod.NamedFunction(fnName) if llvmFn.IsNil() { sig := instr.Method.Type().(*types.Signature) @@ -1213,6 +1212,11 @@ func (c *compilerContext) getInvokeFunction(instr *ssa.CallCommon) llvm.Value { return llvmFn } +func (c *compilerContext) getInvokeFunctionName(instr *ssa.CallCommon) string { + s, _ := c.getTypeCodeName(instr.Value.Type().Underlying()) + return s + "." + instr.Method.Name() + "$invoke" +} + // createInterfaceTypeAssert creates a call to a declared-but-not-defined // $typeassert function for the given interface. This function will be defined // by the interface lowering pass as a type-ID comparison chain, avoiding the diff --git a/testdata/calls.go b/testdata/calls.go index 960443959..fb681366f 100644 --- a/testdata/calls.go +++ b/testdata/calls.go @@ -70,6 +70,7 @@ func main() { // regression testing regression1033() + regression5541() //Test deferred builtins testDeferBuiltinClose() @@ -224,6 +225,46 @@ func foo(bar *Bar) error { return nil } +var regression5541RuntimeClosed, regression5541ModuleClosed int + +type regression5541Closer interface { + Close() +} + +type regression5541Runtime interface { + Foo() + regression5541Closer +} + +type regression5541RuntimeImpl struct{} + +func (*regression5541RuntimeImpl) Foo() { +} + +func (*regression5541RuntimeImpl) Close() { + regression5541RuntimeClosed++ +} + +type regression5541Module struct{} + +func (*regression5541Module) Close() { + regression5541ModuleClosed++ +} + +func regression5541() { + func() { + var runtime regression5541Runtime = ®ression5541RuntimeImpl{} + defer runtime.Close() + + var module regression5541Closer = ®ression5541Module{} + defer module.Close() + }() + + if regression5541RuntimeClosed != 1 || regression5541ModuleClosed != 1 { + println("deferred interface methods were not both called") + } +} + type issue1304 struct { a [0]int // zero-length field b int // field 'b' covers entire struct