From 84db201ae18c889acdefe20c8a903b188328f16d Mon Sep 17 00:00:00 2001 From: Mateusz Poliwczak Date: Fri, 26 Sep 2025 20:47:45 +0200 Subject: [PATCH] cmd/compile: propagate len([]T{}) to make builtin to allow stack allocation Updates #75620 Change-Id: I6a6a6964af4512e30eb4806e1dc7b0fd0835744f Reviewed-on: https://go-review.googlesource.com/c/go/+/707255 Reviewed-by: Keith Randall Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI Auto-Submit: Keith Randall Reviewed-by: Carlos Amedee --- src/cmd/compile/internal/escape/escape.go | 13 ++++++++++++- test/escape_make_non_const.go | 15 +++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/escape/escape.go b/src/cmd/compile/internal/escape/escape.go index 6b34830b3d..59250edfef 100644 --- a/src/cmd/compile/internal/escape/escape.go +++ b/src/cmd/compile/internal/escape/escape.go @@ -563,7 +563,10 @@ func (b *batch) rewriteWithLiterals(n ir.Node, fn *ir.Func) { if ro == nil { base.Fatalf("no ReassignOracle for function %v with closure parent %v", fn, fn.ClosureParent) } - if s := ro.StaticValue(*r); s.Op() == ir.OLITERAL { + + s := ro.StaticValue(*r) + switch s.Op() { + case ir.OLITERAL: lit, ok := s.(*ir.BasicLit) if !ok || lit.Val().Kind() != constant.Int { base.Fatalf("unexpected BasicLit Kind") @@ -577,6 +580,14 @@ func (b *batch) rewriteWithLiterals(n ir.Node, fn *ir.Func) { assignTemp(n.Pos(), *r, n.PtrInit()) *r = ir.NewBasicLit(n.Pos(), (*r).Type(), lit.Val()) } + case ir.OLEN: + x := ro.StaticValue(s.(*ir.UnaryExpr).X) + if x.Op() == ir.OSLICELIT { + x := x.(*ir.CompLitExpr) + // Preserve any side effects of the original expression, then update the value. + assignTemp(n.Pos(), *r, n.PtrInit()) + *r = ir.NewBasicLit(n.Pos(), types.Types[types.TINT], constant.MakeInt64(x.Len)) + } } } case ir.OCONVIFACE: diff --git a/test/escape_make_non_const.go b/test/escape_make_non_const.go index 7a9b28d5e3..11854ac4f4 100644 --- a/test/escape_make_non_const.go +++ b/test/escape_make_non_const.go @@ -106,3 +106,18 @@ type m struct { func newM(l int) m { // ERROR "can inline" return m{make(map[string]int, l)} // ERROR "make.*escapes to heap" } + +//go:noinline +func testLenOfSliceLit() { + ints := []int{0, 1, 2, 3, 4, 5} // ERROR "\[\]int\{\.\.\.\} does not escape"' + _ = make([]int, len(ints)) // ERROR "make\(\[\]int, 6\) does not escape" + _ = allocLenOf(ints) // ERROR "inlining call", "make\(\[\]int, 6\) does not escape" + + _ = make([]int, 2, len(ints)) // ERROR "make\(\[\]int, 2, 6\) does not escape" + _ = make([]int, len(ints), 2) // ERROR "make\(\[\]int, len\(ints\), 2\) does not escape" + _ = make([]int, 10, len(ints)) // ERROR "make\(\[\]int, 10, 6\) does not escape" +} + +func allocLenOf(s []int) []int { // ERROR "can inline" "s does not escape" + return make([]int, len(s)) // ERROR "escapes to heap" +} -- 2.52.0