Skip to content

Commit ceffdc8

Browse files
committed
cmd/compile: implement slice-to-array conversions
The conversion T(x) is implemented as *(*T)(x). Accordingly, runtime panic messages for (*T)(x) are made more general. Fixes #46505. Change-Id: I76317c0878b6a5908299506d392eed50d7ef6523 Reviewed-on: https://go-review.googlesource.com/c/go/+/430415 Reviewed-by: Cuong Manh Le <[email protected]> Reviewed-by: Jenny Rakoczy <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Matthew Dempsky <[email protected]> Reviewed-by: Keith Randall <[email protected]>
1 parent 29153be commit ceffdc8

File tree

15 files changed

+210
-148
lines changed

15 files changed

+210
-148
lines changed

src/cmd/compile/internal/escape/expr.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
126126
case ir.OITAB, ir.OIDATA, ir.OSPTR:
127127
n := n.(*ir.UnaryExpr)
128128
e.expr(k, n.X)
129+
case ir.OSLICE2ARR:
130+
// Converting a slice to array is effectively a deref.
131+
n := n.(*ir.ConvExpr)
132+
e.expr(k.deref(n, "slice-to-array"), n.X)
129133
case ir.OSLICE2ARRPTR:
130134
// the slice pointer flows directly to the result
131135
n := n.(*ir.ConvExpr)

src/cmd/compile/internal/ir/expr.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ func (n *ConvExpr) SetOp(op Op) {
289289
switch op {
290290
default:
291291
panic(n.no("SetOp " + op.String()))
292-
case OCONV, OCONVIFACE, OCONVIDATA, OCONVNOP, OBYTES2STR, OBYTES2STRTMP, ORUNES2STR, OSTR2BYTES, OSTR2BYTESTMP, OSTR2RUNES, ORUNESTR, OSLICE2ARRPTR:
292+
case OCONV, OCONVIFACE, OCONVIDATA, OCONVNOP, OBYTES2STR, OBYTES2STRTMP, ORUNES2STR, OSTR2BYTES, OSTR2BYTESTMP, OSTR2RUNES, ORUNESTR, OSLICE2ARR, OSLICE2ARRPTR:
293293
n.op = op
294294
}
295295
}

src/cmd/compile/internal/ir/fmt.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ var OpPrec = []int{
208208
OPRINT: 8,
209209
ORUNESTR: 8,
210210
OSIZEOF: 8,
211+
OSLICE2ARR: 8,
211212
OSLICE2ARRPTR: 8,
212213
OSTR2BYTES: 8,
213214
OSTR2RUNES: 8,
@@ -753,6 +754,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
753754
OSTR2BYTES,
754755
OSTR2RUNES,
755756
ORUNESTR,
757+
OSLICE2ARR,
756758
OSLICE2ARRPTR:
757759
n := n.(*ConvExpr)
758760
if n.Type() == nil || n.Type().Sym() == nil {

src/cmd/compile/internal/ir/node.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ const (
134134
OSTR2BYTES // Type(X) (Type is []byte, X is a string)
135135
OSTR2BYTESTMP // Type(X) (Type is []byte, X is a string, ephemeral)
136136
OSTR2RUNES // Type(X) (Type is []rune, X is a string)
137+
OSLICE2ARR // Type(X) (Type is [N]T, X is a []T)
137138
OSLICE2ARRPTR // Type(X) (Type is *[N]T, X is a []T)
138139
// X = Y or (if Def=true) X := Y
139140
// If Def, then Init includes a DCL node for X.

src/cmd/compile/internal/ir/op_string.go

Lines changed: 137 additions & 136 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/cmd/compile/internal/typecheck/iexport.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1974,7 +1974,7 @@ func (w *exportWriter) expr(n ir.Node) {
19741974
w.expr(n.Y)
19751975
w.typ(n.Type())
19761976

1977-
case ir.OCONV, ir.OCONVIFACE, ir.OCONVIDATA, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR, ir.OSLICE2ARRPTR:
1977+
case ir.OCONV, ir.OCONVIFACE, ir.OCONVIDATA, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR, ir.OSLICE2ARR, ir.OSLICE2ARRPTR:
19781978
n := n.(*ir.ConvExpr)
19791979
w.op(n.Op())
19801980
w.pos(n.Pos())

src/cmd/compile/internal/typecheck/iimport.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1484,7 +1484,7 @@ func (r *importReader) node() ir.Node {
14841484
n.SetType(r.typ())
14851485
return n
14861486

1487-
case ir.OCONV, ir.OCONVIFACE, ir.OCONVIDATA, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR, ir.OSLICE2ARRPTR:
1487+
case ir.OCONV, ir.OCONVIFACE, ir.OCONVIDATA, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR, ir.OSLICE2ARR, ir.OSLICE2ARRPTR:
14881488
n := ir.NewConvExpr(r.pos(), op, r.typ(), r.expr())
14891489
n.SetImplicit(r.bool())
14901490
return n

src/cmd/compile/internal/typecheck/subr.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -579,11 +579,16 @@ func Convertop(srcConstant bool, src, dst *types.Type) (ir.Op, string) {
579579
return ir.OCONVNOP, ""
580580
}
581581

582-
// 11. src is a slice and dst is a pointer-to-array.
582+
// 11. src is a slice and dst is an array or pointer-to-array.
583583
// They must have same element type.
584-
if src.IsSlice() && dst.IsPtr() && dst.Elem().IsArray() &&
585-
types.Identical(src.Elem(), dst.Elem().Elem()) {
586-
return ir.OSLICE2ARRPTR, ""
584+
if src.IsSlice() {
585+
if dst.IsArray() && types.Identical(src.Elem(), dst.Elem()) {
586+
return ir.OSLICE2ARR, ""
587+
}
588+
if dst.IsPtr() && dst.Elem().IsArray() &&
589+
types.Identical(src.Elem(), dst.Elem().Elem()) {
590+
return ir.OSLICE2ARRPTR, ""
591+
}
587592
}
588593

589594
return ir.OXXX, ""

src/cmd/compile/internal/walk/convert.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,3 +503,21 @@ func walkCheckPtrArithmetic(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
503503

504504
return cheap
505505
}
506+
507+
// walkSliceToArray walks an OSLICE2ARR expression.
508+
func walkSliceToArray(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
509+
// Replace T(x) with *(*T)(x).
510+
conv := typecheck.Expr(ir.NewConvExpr(base.Pos, ir.OCONV, types.NewPtr(n.Type()), n.X)).(*ir.ConvExpr)
511+
deref := typecheck.Expr(ir.NewStarExpr(base.Pos, conv)).(*ir.StarExpr)
512+
513+
// The OSLICE2ARRPTR conversion handles checking the slice length,
514+
// so the dereference can't fail.
515+
//
516+
// However, this is more than just an optimization: if T is a
517+
// zero-length array, then x (and thus (*T)(x)) can be nil, but T(x)
518+
// should *not* panic. So suppressing the nil check here is
519+
// necessary for correctness in that case.
520+
deref.SetBounded(true)
521+
522+
return walkExpr(deref, init)
523+
}

src/cmd/compile/internal/walk/expr.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,10 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
227227
n := n.(*ir.ConvExpr)
228228
return walkConv(n, init)
229229

230+
case ir.OSLICE2ARR:
231+
n := n.(*ir.ConvExpr)
232+
return walkSliceToArray(n, init)
233+
230234
case ir.OSLICE2ARRPTR:
231235
n := n.(*ir.ConvExpr)
232236
n.X = walkExpr(n.X, init)

0 commit comments

Comments
 (0)