mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
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 <khr@google.com> Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: David Chase <drchase@google.com> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
ac9d777caf
commit
a141c58c85
@ -9,6 +9,7 @@ import (
|
||||
"go/constant"
|
||||
"go/token"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/ir"
|
||||
@ -866,14 +867,22 @@ func subst(n ir.Node, m map[*ir.Name]ir.Node) (ir.Node, bool) {
|
||||
}
|
||||
x = ir.Copy(x)
|
||||
ir.EditChildrenWithHidden(x, edit)
|
||||
if x, ok := x.(*ir.ConvExpr); ok && x.X.Op() == ir.OLITERAL {
|
||||
if x, ok := truncate(x.X, x.Type()); ok {
|
||||
|
||||
// TODO: handle more operations, see details discussion in go.dev/cl/466277.
|
||||
switch x.Op() {
|
||||
case ir.OCONV:
|
||||
x := x.(*ir.ConvExpr)
|
||||
if x.X.Op() == ir.OLITERAL {
|
||||
if x, ok := truncate(x.X, x.Type()); ok {
|
||||
return x
|
||||
}
|
||||
valid = false
|
||||
return x
|
||||
}
|
||||
valid = false
|
||||
return x
|
||||
case ir.OADDSTR:
|
||||
return addStr(x.(*ir.AddStringExpr))
|
||||
}
|
||||
return typecheck.EvalConst(x)
|
||||
return x
|
||||
}
|
||||
n = edit(n)
|
||||
return n, valid
|
||||
@ -909,6 +918,51 @@ func truncate(c ir.Node, t *types.Type) (ir.Node, bool) {
|
||||
return c, true
|
||||
}
|
||||
|
||||
func addStr(n *ir.AddStringExpr) ir.Node {
|
||||
// Merge adjacent constants in the argument list.
|
||||
s := n.List
|
||||
need := 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
if i == 0 || !ir.IsConst(s[i-1], constant.String) || !ir.IsConst(s[i], constant.String) {
|
||||
// Can't merge s[i] into s[i-1]; need a slot in the list.
|
||||
need++
|
||||
}
|
||||
}
|
||||
if need == len(s) {
|
||||
return n
|
||||
}
|
||||
if need == 1 {
|
||||
var strs []string
|
||||
for _, c := range s {
|
||||
strs = append(strs, ir.StringVal(c))
|
||||
}
|
||||
return typecheck.OrigConst(n, constant.MakeString(strings.Join(strs, "")))
|
||||
}
|
||||
newList := make([]ir.Node, 0, need)
|
||||
for i := 0; i < len(s); i++ {
|
||||
if ir.IsConst(s[i], constant.String) && i+1 < len(s) && ir.IsConst(s[i+1], constant.String) {
|
||||
// merge from i up to but not including i2
|
||||
var strs []string
|
||||
i2 := i
|
||||
for i2 < len(s) && ir.IsConst(s[i2], constant.String) {
|
||||
strs = append(strs, ir.StringVal(s[i2]))
|
||||
i2++
|
||||
}
|
||||
|
||||
nl := ir.Copy(n).(*ir.AddStringExpr)
|
||||
nl.List = s[i:i2]
|
||||
newList = append(newList, typecheck.OrigConst(nl, constant.MakeString(strings.Join(strs, ""))))
|
||||
i = i2 - 1
|
||||
} else {
|
||||
newList = append(newList, s[i])
|
||||
}
|
||||
}
|
||||
|
||||
nn := ir.Copy(n).(*ir.AddStringExpr)
|
||||
nn.List = newList
|
||||
return nn
|
||||
}
|
||||
|
||||
const wrapGlobalMapInitSizeThreshold = 20
|
||||
|
||||
// tryWrapGlobalMapInit examines the node 'n' to see if it is a map
|
||||
|
14
test/fixedbugs/issue58439.go
Normal file
14
test/fixedbugs/issue58439.go
Normal file
@ -0,0 +1,14 @@
|
||||
// compile -d=inlstaticinit
|
||||
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
var x = f(-1)
|
||||
var y = f(64)
|
||||
|
||||
func f(x int) int {
|
||||
return 1 << x
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user