Skip to content

Commit a141c58

Browse files
committed
cmd/compile: handle string concatenation in static init inliner
Static init inliner is using typecheck.EvalConst to handle string concatenation expressions. But static init inliner may reveal constant expressions after substitution, and the compiler needs to evaluate those expressions in non-constant semantic. Using typecheck.EvalConst, which always evaluates expressions in constant semantic, is not the right choice. For safety, this CL fold the logic to handle string concatenation to static init inliner, so there won't be regression in handling constant expressions in non-constant semantic. And also, future CL can simplify typecheck.EvalConst logic. Updates #58293 Updates #58339 Fixes #58439 Change-Id: I74068d99c245938e576afe9460cbd2b39677bbff Reviewed-on: https://go-review.googlesource.com/c/go/+/466277 Reviewed-by: Keith Randall <[email protected]> Run-TryBot: Cuong Manh Le <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: David Chase <[email protected]> Reviewed-by: Keith Randall <[email protected]>
1 parent ac9d777 commit a141c58

File tree

2 files changed

+73
-5
lines changed

2 files changed

+73
-5
lines changed

src/cmd/compile/internal/staticinit/sched.go

+59-5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"go/constant"
1010
"go/token"
1111
"os"
12+
"strings"
1213

1314
"cmd/compile/internal/base"
1415
"cmd/compile/internal/ir"
@@ -866,14 +867,22 @@ func subst(n ir.Node, m map[*ir.Name]ir.Node) (ir.Node, bool) {
866867
}
867868
x = ir.Copy(x)
868869
ir.EditChildrenWithHidden(x, edit)
869-
if x, ok := x.(*ir.ConvExpr); ok && x.X.Op() == ir.OLITERAL {
870-
if x, ok := truncate(x.X, x.Type()); ok {
870+
871+
// TODO: handle more operations, see details discussion in go.dev/cl/466277.
872+
switch x.Op() {
873+
case ir.OCONV:
874+
x := x.(*ir.ConvExpr)
875+
if x.X.Op() == ir.OLITERAL {
876+
if x, ok := truncate(x.X, x.Type()); ok {
877+
return x
878+
}
879+
valid = false
871880
return x
872881
}
873-
valid = false
874-
return x
882+
case ir.OADDSTR:
883+
return addStr(x.(*ir.AddStringExpr))
875884
}
876-
return typecheck.EvalConst(x)
885+
return x
877886
}
878887
n = edit(n)
879888
return n, valid
@@ -909,6 +918,51 @@ func truncate(c ir.Node, t *types.Type) (ir.Node, bool) {
909918
return c, true
910919
}
911920

921+
func addStr(n *ir.AddStringExpr) ir.Node {
922+
// Merge adjacent constants in the argument list.
923+
s := n.List
924+
need := 0
925+
for i := 0; i < len(s); i++ {
926+
if i == 0 || !ir.IsConst(s[i-1], constant.String) || !ir.IsConst(s[i], constant.String) {
927+
// Can't merge s[i] into s[i-1]; need a slot in the list.
928+
need++
929+
}
930+
}
931+
if need == len(s) {
932+
return n
933+
}
934+
if need == 1 {
935+
var strs []string
936+
for _, c := range s {
937+
strs = append(strs, ir.StringVal(c))
938+
}
939+
return typecheck.OrigConst(n, constant.MakeString(strings.Join(strs, "")))
940+
}
941+
newList := make([]ir.Node, 0, need)
942+
for i := 0; i < len(s); i++ {
943+
if ir.IsConst(s[i], constant.String) && i+1 < len(s) && ir.IsConst(s[i+1], constant.String) {
944+
// merge from i up to but not including i2
945+
var strs []string
946+
i2 := i
947+
for i2 < len(s) && ir.IsConst(s[i2], constant.String) {
948+
strs = append(strs, ir.StringVal(s[i2]))
949+
i2++
950+
}
951+
952+
nl := ir.Copy(n).(*ir.AddStringExpr)
953+
nl.List = s[i:i2]
954+
newList = append(newList, typecheck.OrigConst(nl, constant.MakeString(strings.Join(strs, ""))))
955+
i = i2 - 1
956+
} else {
957+
newList = append(newList, s[i])
958+
}
959+
}
960+
961+
nn := ir.Copy(n).(*ir.AddStringExpr)
962+
nn.List = newList
963+
return nn
964+
}
965+
912966
const wrapGlobalMapInitSizeThreshold = 20
913967

914968
// tryWrapGlobalMapInit examines the node 'n' to see if it is a map

test/fixedbugs/issue58439.go

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// compile -d=inlstaticinit
2+
3+
// Copyright 2023 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package p
8+
9+
var x = f(-1)
10+
var y = f(64)
11+
12+
func f(x int) int {
13+
return 1 << x
14+
}

0 commit comments

Comments
 (0)