From 3df9df8d6a1a140239e4cba0d0595bdab2ba9c60 Mon Sep 17 00:00:00 2001 From: hopehook Date: Fri, 8 Apr 2022 17:59:05 +0800 Subject: [PATCH] cmd/compile: fix missing source information in ssa view Endlineno is lost when we call "genericSubst" to create the new instantiation of the generic function. This will cause "readFuncLines" to fail to read the target function. To fix this issue, as @mdempsky pointed out, add the line in cmd/compile/internal/noder/stencil.go: newf.Endlineno = gf.Endlineno Fixes #51988 Change-Id: Ib408e4ed0ceb68df8dedda4fb551309e8385aada Reviewed-on: https://go-review.googlesource.com/c/go/+/399057 Reviewed-by: Matthew Dempsky Run-TryBot: Matthew Dempsky Auto-Submit: Matthew Dempsky TryBot-Result: Gopher Robot Reviewed-by: Austin Clements Reviewed-by: Than McIntosh --- src/cmd/compile/internal/noder/stencil.go | 1 + src/runtime/callers_test.go | 30 +++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index eeac8d8de7..41435a7afe 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -741,6 +741,7 @@ func (g *genInst) genericSubst(newsym *types.Sym, nameNode *ir.Name, tparams []* // Pos of the instantiated function is same as the generic function newf := ir.NewFunc(gf.Pos()) newf.Pragma = gf.Pragma // copy over pragmas from generic function to stenciled implementation. + newf.Endlineno = gf.Endlineno newf.Nname = ir.NewNameAt(gf.Pos(), newsym) newf.Nname.Func = newf newf.Nname.Defn = newf diff --git a/src/runtime/callers_test.go b/src/runtime/callers_test.go index 3cf3fbe5ac..d245cbd2d2 100644 --- a/src/runtime/callers_test.go +++ b/src/runtime/callers_test.go @@ -309,3 +309,33 @@ func TestCallersDeferNilFuncPanicWithLoop(t *testing.T) { // function exit, rather than at the defer statement. state = 2 } + +// issue #51988 +// Func.Endlineno was lost when instantiating generic functions, leading to incorrect +// stack trace positions. +func TestCallersEndlineno(t *testing.T) { + testNormalEndlineno(t) + testGenericEndlineno[int](t) +} + +func testNormalEndlineno(t *testing.T) { + defer testCallerLine(t, callerLine(t, 0)+1) +} + +func testGenericEndlineno[_ any](t *testing.T) { + defer testCallerLine(t, callerLine(t, 0)+1) +} + +func testCallerLine(t *testing.T, want int) { + if have := callerLine(t, 1); have != want { + t.Errorf("callerLine(1) returned %d, but want %d\n", have, want) + } +} + +func callerLine(t *testing.T, skip int) int { + _, _, line, ok := runtime.Caller(skip + 1) + if !ok { + t.Fatalf("runtime.Caller(%d) failed", skip+1) + } + return line +} -- 2.48.1