From: Matthew Dempsky Date: Mon, 12 Sep 2022 20:01:57 +0000 (-0700) Subject: cmd/compile: implement slice-to-array conversions X-Git-Tag: go1.20rc1~990 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=ceffdc8545c3155b030de9e91d399dc34bd3c678;p=gostls13.git 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 Reviewed-by: Jenny Rakoczy TryBot-Result: Gopher Robot Run-TryBot: Matthew Dempsky Reviewed-by: Keith Randall --- diff --git a/src/cmd/compile/internal/escape/expr.go b/src/cmd/compile/internal/escape/expr.go index fd758bbf20..fc56530969 100644 --- a/src/cmd/compile/internal/escape/expr.go +++ b/src/cmd/compile/internal/escape/expr.go @@ -126,6 +126,10 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) { case ir.OITAB, ir.OIDATA, ir.OSPTR: n := n.(*ir.UnaryExpr) e.expr(k, n.X) + case ir.OSLICE2ARR: + // Converting a slice to array is effectively a deref. + n := n.(*ir.ConvExpr) + e.expr(k.deref(n, "slice-to-array"), n.X) case ir.OSLICE2ARRPTR: // the slice pointer flows directly to the result n := n.(*ir.ConvExpr) diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go index ff315bd027..a481b14f8b 100644 --- a/src/cmd/compile/internal/ir/expr.go +++ b/src/cmd/compile/internal/ir/expr.go @@ -289,7 +289,7 @@ func (n *ConvExpr) SetOp(op Op) { switch op { default: panic(n.no("SetOp " + op.String())) - case OCONV, OCONVIFACE, OCONVIDATA, OCONVNOP, OBYTES2STR, OBYTES2STRTMP, ORUNES2STR, OSTR2BYTES, OSTR2BYTESTMP, OSTR2RUNES, ORUNESTR, OSLICE2ARRPTR: + case OCONV, OCONVIFACE, OCONVIDATA, OCONVNOP, OBYTES2STR, OBYTES2STRTMP, ORUNES2STR, OSTR2BYTES, OSTR2BYTESTMP, OSTR2RUNES, ORUNESTR, OSLICE2ARR, OSLICE2ARRPTR: n.op = op } } diff --git a/src/cmd/compile/internal/ir/fmt.go b/src/cmd/compile/internal/ir/fmt.go index d051c88a29..7a0d8a62c1 100644 --- a/src/cmd/compile/internal/ir/fmt.go +++ b/src/cmd/compile/internal/ir/fmt.go @@ -208,6 +208,7 @@ var OpPrec = []int{ OPRINT: 8, ORUNESTR: 8, OSIZEOF: 8, + OSLICE2ARR: 8, OSLICE2ARRPTR: 8, OSTR2BYTES: 8, OSTR2RUNES: 8, @@ -753,6 +754,7 @@ func exprFmt(n Node, s fmt.State, prec int) { OSTR2BYTES, OSTR2RUNES, ORUNESTR, + OSLICE2ARR, OSLICE2ARRPTR: n := n.(*ConvExpr) if n.Type() == nil || n.Type().Sym() == nil { diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go index 7a4fb02f25..bda3957af9 100644 --- a/src/cmd/compile/internal/ir/node.go +++ b/src/cmd/compile/internal/ir/node.go @@ -134,6 +134,7 @@ const ( OSTR2BYTES // Type(X) (Type is []byte, X is a string) OSTR2BYTESTMP // Type(X) (Type is []byte, X is a string, ephemeral) OSTR2RUNES // Type(X) (Type is []rune, X is a string) + OSLICE2ARR // Type(X) (Type is [N]T, X is a []T) OSLICE2ARRPTR // Type(X) (Type is *[N]T, X is a []T) // X = Y or (if Def=true) X := Y // If Def, then Init includes a DCL node for X. diff --git a/src/cmd/compile/internal/ir/op_string.go b/src/cmd/compile/internal/ir/op_string.go index e44168c7ba..d84a08e2a1 100644 --- a/src/cmd/compile/internal/ir/op_string.go +++ b/src/cmd/compile/internal/ir/op_string.go @@ -28,145 +28,146 @@ func _() { _ = x[OSTR2BYTES-17] _ = x[OSTR2BYTESTMP-18] _ = x[OSTR2RUNES-19] - _ = x[OSLICE2ARRPTR-20] - _ = x[OAS-21] - _ = x[OAS2-22] - _ = x[OAS2DOTTYPE-23] - _ = x[OAS2FUNC-24] - _ = x[OAS2MAPR-25] - _ = x[OAS2RECV-26] - _ = x[OASOP-27] - _ = x[OCALL-28] - _ = x[OCALLFUNC-29] - _ = x[OCALLMETH-30] - _ = x[OCALLINTER-31] - _ = x[OCAP-32] - _ = x[OCLOSE-33] - _ = x[OCLOSURE-34] - _ = x[OCOMPLIT-35] - _ = x[OMAPLIT-36] - _ = x[OSTRUCTLIT-37] - _ = x[OARRAYLIT-38] - _ = x[OSLICELIT-39] - _ = x[OPTRLIT-40] - _ = x[OCONV-41] - _ = x[OCONVIFACE-42] - _ = x[OCONVIDATA-43] - _ = x[OCONVNOP-44] - _ = x[OCOPY-45] - _ = x[ODCL-46] - _ = x[ODCLFUNC-47] - _ = x[ODCLCONST-48] - _ = x[ODCLTYPE-49] - _ = x[ODELETE-50] - _ = x[ODOT-51] - _ = x[ODOTPTR-52] - _ = x[ODOTMETH-53] - _ = x[ODOTINTER-54] - _ = x[OXDOT-55] - _ = x[ODOTTYPE-56] - _ = x[ODOTTYPE2-57] - _ = x[OEQ-58] - _ = x[ONE-59] - _ = x[OLT-60] - _ = x[OLE-61] - _ = x[OGE-62] - _ = x[OGT-63] - _ = x[ODEREF-64] - _ = x[OINDEX-65] - _ = x[OINDEXMAP-66] - _ = x[OKEY-67] - _ = x[OSTRUCTKEY-68] - _ = x[OLEN-69] - _ = x[OMAKE-70] - _ = x[OMAKECHAN-71] - _ = x[OMAKEMAP-72] - _ = x[OMAKESLICE-73] - _ = x[OMAKESLICECOPY-74] - _ = x[OMUL-75] - _ = x[ODIV-76] - _ = x[OMOD-77] - _ = x[OLSH-78] - _ = x[ORSH-79] - _ = x[OAND-80] - _ = x[OANDNOT-81] - _ = x[ONEW-82] - _ = x[ONOT-83] - _ = x[OBITNOT-84] - _ = x[OPLUS-85] - _ = x[ONEG-86] - _ = x[OOROR-87] - _ = x[OPANIC-88] - _ = x[OPRINT-89] - _ = x[OPRINTN-90] - _ = x[OPAREN-91] - _ = x[OSEND-92] - _ = x[OSLICE-93] - _ = x[OSLICEARR-94] - _ = x[OSLICESTR-95] - _ = x[OSLICE3-96] - _ = x[OSLICE3ARR-97] - _ = x[OSLICEHEADER-98] - _ = x[OSTRINGHEADER-99] - _ = x[ORECOVER-100] - _ = x[ORECOVERFP-101] - _ = x[ORECV-102] - _ = x[ORUNESTR-103] - _ = x[OSELRECV2-104] - _ = x[OREAL-105] - _ = x[OIMAG-106] - _ = x[OCOMPLEX-107] - _ = x[OALIGNOF-108] - _ = x[OOFFSETOF-109] - _ = x[OSIZEOF-110] - _ = x[OUNSAFEADD-111] - _ = x[OUNSAFESLICE-112] - _ = x[OUNSAFESLICEDATA-113] - _ = x[OUNSAFESTRING-114] - _ = x[OUNSAFESTRINGDATA-115] - _ = x[OMETHEXPR-116] - _ = x[OMETHVALUE-117] - _ = x[OBLOCK-118] - _ = x[OBREAK-119] - _ = x[OCASE-120] - _ = x[OCONTINUE-121] - _ = x[ODEFER-122] - _ = x[OFALL-123] - _ = x[OFOR-124] - _ = x[OGOTO-125] - _ = x[OIF-126] - _ = x[OLABEL-127] - _ = x[OGO-128] - _ = x[ORANGE-129] - _ = x[ORETURN-130] - _ = x[OSELECT-131] - _ = x[OSWITCH-132] - _ = x[OTYPESW-133] - _ = x[OFUNCINST-134] - _ = x[OINLCALL-135] - _ = x[OEFACE-136] - _ = x[OITAB-137] - _ = x[OIDATA-138] - _ = x[OSPTR-139] - _ = x[OCFUNC-140] - _ = x[OCHECKNIL-141] - _ = x[ORESULT-142] - _ = x[OINLMARK-143] - _ = x[OLINKSYMOFFSET-144] - _ = x[OJUMPTABLE-145] - _ = x[ODYNAMICDOTTYPE-146] - _ = x[ODYNAMICDOTTYPE2-147] - _ = x[ODYNAMICTYPE-148] - _ = x[OTAILCALL-149] - _ = x[OGETG-150] - _ = x[OGETCALLERPC-151] - _ = x[OGETCALLERSP-152] - _ = x[OEND-153] + _ = x[OSLICE2ARR-20] + _ = x[OSLICE2ARRPTR-21] + _ = x[OAS-22] + _ = x[OAS2-23] + _ = x[OAS2DOTTYPE-24] + _ = x[OAS2FUNC-25] + _ = x[OAS2MAPR-26] + _ = x[OAS2RECV-27] + _ = x[OASOP-28] + _ = x[OCALL-29] + _ = x[OCALLFUNC-30] + _ = x[OCALLMETH-31] + _ = x[OCALLINTER-32] + _ = x[OCAP-33] + _ = x[OCLOSE-34] + _ = x[OCLOSURE-35] + _ = x[OCOMPLIT-36] + _ = x[OMAPLIT-37] + _ = x[OSTRUCTLIT-38] + _ = x[OARRAYLIT-39] + _ = x[OSLICELIT-40] + _ = x[OPTRLIT-41] + _ = x[OCONV-42] + _ = x[OCONVIFACE-43] + _ = x[OCONVIDATA-44] + _ = x[OCONVNOP-45] + _ = x[OCOPY-46] + _ = x[ODCL-47] + _ = x[ODCLFUNC-48] + _ = x[ODCLCONST-49] + _ = x[ODCLTYPE-50] + _ = x[ODELETE-51] + _ = x[ODOT-52] + _ = x[ODOTPTR-53] + _ = x[ODOTMETH-54] + _ = x[ODOTINTER-55] + _ = x[OXDOT-56] + _ = x[ODOTTYPE-57] + _ = x[ODOTTYPE2-58] + _ = x[OEQ-59] + _ = x[ONE-60] + _ = x[OLT-61] + _ = x[OLE-62] + _ = x[OGE-63] + _ = x[OGT-64] + _ = x[ODEREF-65] + _ = x[OINDEX-66] + _ = x[OINDEXMAP-67] + _ = x[OKEY-68] + _ = x[OSTRUCTKEY-69] + _ = x[OLEN-70] + _ = x[OMAKE-71] + _ = x[OMAKECHAN-72] + _ = x[OMAKEMAP-73] + _ = x[OMAKESLICE-74] + _ = x[OMAKESLICECOPY-75] + _ = x[OMUL-76] + _ = x[ODIV-77] + _ = x[OMOD-78] + _ = x[OLSH-79] + _ = x[ORSH-80] + _ = x[OAND-81] + _ = x[OANDNOT-82] + _ = x[ONEW-83] + _ = x[ONOT-84] + _ = x[OBITNOT-85] + _ = x[OPLUS-86] + _ = x[ONEG-87] + _ = x[OOROR-88] + _ = x[OPANIC-89] + _ = x[OPRINT-90] + _ = x[OPRINTN-91] + _ = x[OPAREN-92] + _ = x[OSEND-93] + _ = x[OSLICE-94] + _ = x[OSLICEARR-95] + _ = x[OSLICESTR-96] + _ = x[OSLICE3-97] + _ = x[OSLICE3ARR-98] + _ = x[OSLICEHEADER-99] + _ = x[OSTRINGHEADER-100] + _ = x[ORECOVER-101] + _ = x[ORECOVERFP-102] + _ = x[ORECV-103] + _ = x[ORUNESTR-104] + _ = x[OSELRECV2-105] + _ = x[OREAL-106] + _ = x[OIMAG-107] + _ = x[OCOMPLEX-108] + _ = x[OALIGNOF-109] + _ = x[OOFFSETOF-110] + _ = x[OSIZEOF-111] + _ = x[OUNSAFEADD-112] + _ = x[OUNSAFESLICE-113] + _ = x[OUNSAFESLICEDATA-114] + _ = x[OUNSAFESTRING-115] + _ = x[OUNSAFESTRINGDATA-116] + _ = x[OMETHEXPR-117] + _ = x[OMETHVALUE-118] + _ = x[OBLOCK-119] + _ = x[OBREAK-120] + _ = x[OCASE-121] + _ = x[OCONTINUE-122] + _ = x[ODEFER-123] + _ = x[OFALL-124] + _ = x[OFOR-125] + _ = x[OGOTO-126] + _ = x[OIF-127] + _ = x[OLABEL-128] + _ = x[OGO-129] + _ = x[ORANGE-130] + _ = x[ORETURN-131] + _ = x[OSELECT-132] + _ = x[OSWITCH-133] + _ = x[OTYPESW-134] + _ = x[OFUNCINST-135] + _ = x[OINLCALL-136] + _ = x[OEFACE-137] + _ = x[OITAB-138] + _ = x[OIDATA-139] + _ = x[OSPTR-140] + _ = x[OCFUNC-141] + _ = x[OCHECKNIL-142] + _ = x[ORESULT-143] + _ = x[OINLMARK-144] + _ = x[OLINKSYMOFFSET-145] + _ = x[OJUMPTABLE-146] + _ = x[ODYNAMICDOTTYPE-147] + _ = x[ODYNAMICDOTTYPE2-148] + _ = x[ODYNAMICTYPE-149] + _ = x[OTAILCALL-150] + _ = x[OGETG-151] + _ = x[OGETCALLERPC-152] + _ = x[OGETCALLERSP-153] + _ = x[OEND-154] } -const _Op_name = "XXXNAMENONAMETYPELITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVIDATACONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERSTRINGHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2REALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEUNSAFESLICEDATAUNSAFESTRINGUNSAFESTRINGDATAMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTINLCALLEFACEITABIDATASPTRCFUNCCHECKNILRESULTINLMARKLINKSYMOFFSETJUMPTABLEDYNAMICDOTTYPEDYNAMICDOTTYPE2DYNAMICTYPETAILCALLGETGGETCALLERPCGETCALLERSPEND" +const _Op_name = "XXXNAMENONAMETYPELITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVIDATACONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERSTRINGHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2REALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEUNSAFESLICEDATAUNSAFESTRINGUNSAFESTRINGDATAMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTINLCALLEFACEITABIDATASPTRCFUNCCHECKNILRESULTINLMARKLINKSYMOFFSETJUMPTABLEDYNAMICDOTTYPEDYNAMICDOTTYPE2DYNAMICTYPETAILCALLGETGGETCALLERPCGETCALLERSPEND" -var _Op_index = [...]uint16{0, 3, 7, 13, 17, 24, 27, 30, 33, 35, 38, 44, 48, 54, 60, 69, 81, 90, 99, 111, 120, 132, 134, 137, 147, 154, 161, 168, 172, 176, 184, 192, 201, 204, 209, 216, 223, 229, 238, 246, 254, 260, 264, 273, 282, 289, 293, 296, 303, 311, 318, 324, 327, 333, 340, 348, 352, 359, 367, 369, 371, 373, 375, 377, 379, 384, 389, 397, 400, 409, 412, 416, 424, 431, 440, 453, 456, 459, 462, 465, 468, 471, 477, 480, 483, 489, 493, 496, 500, 505, 510, 516, 521, 525, 530, 538, 546, 552, 561, 572, 584, 591, 600, 604, 611, 619, 623, 627, 634, 641, 649, 655, 664, 675, 690, 702, 718, 726, 735, 740, 745, 749, 757, 762, 766, 769, 773, 775, 780, 782, 787, 793, 799, 805, 811, 819, 826, 831, 835, 840, 844, 849, 857, 863, 870, 883, 892, 906, 921, 932, 940, 944, 955, 966, 969} +var _Op_index = [...]uint16{0, 3, 7, 13, 17, 24, 27, 30, 33, 35, 38, 44, 48, 54, 60, 69, 81, 90, 99, 111, 120, 129, 141, 143, 146, 156, 163, 170, 177, 181, 185, 193, 201, 210, 213, 218, 225, 232, 238, 247, 255, 263, 269, 273, 282, 291, 298, 302, 305, 312, 320, 327, 333, 336, 342, 349, 357, 361, 368, 376, 378, 380, 382, 384, 386, 388, 393, 398, 406, 409, 418, 421, 425, 433, 440, 449, 462, 465, 468, 471, 474, 477, 480, 486, 489, 492, 498, 502, 505, 509, 514, 519, 525, 530, 534, 539, 547, 555, 561, 570, 581, 593, 600, 609, 613, 620, 628, 632, 636, 643, 650, 658, 664, 673, 684, 699, 711, 727, 735, 744, 749, 754, 758, 766, 771, 775, 778, 782, 784, 789, 791, 796, 802, 808, 814, 820, 828, 835, 840, 844, 849, 853, 858, 866, 872, 879, 892, 901, 915, 930, 941, 949, 953, 964, 975, 978} func (i Op) String() string { if i >= Op(len(_Op_index)-1) { diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 848408d240..3e65425398 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -1974,7 +1974,7 @@ func (w *exportWriter) expr(n ir.Node) { w.expr(n.Y) w.typ(n.Type()) - case ir.OCONV, ir.OCONVIFACE, ir.OCONVIDATA, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR, ir.OSLICE2ARRPTR: + case ir.OCONV, ir.OCONVIFACE, ir.OCONVIDATA, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR, ir.OSLICE2ARR, ir.OSLICE2ARRPTR: n := n.(*ir.ConvExpr) w.op(n.Op()) w.pos(n.Pos()) diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 80ae0259e8..533ee99c21 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -1484,7 +1484,7 @@ func (r *importReader) node() ir.Node { n.SetType(r.typ()) return n - case ir.OCONV, ir.OCONVIFACE, ir.OCONVIDATA, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR, ir.OSLICE2ARRPTR: + case ir.OCONV, ir.OCONVIFACE, ir.OCONVIDATA, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR, ir.OSLICE2ARR, ir.OSLICE2ARRPTR: n := ir.NewConvExpr(r.pos(), op, r.typ(), r.expr()) n.SetImplicit(r.bool()) return n diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index eab71556d3..f616b13781 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -579,11 +579,16 @@ func Convertop(srcConstant bool, src, dst *types.Type) (ir.Op, string) { return ir.OCONVNOP, "" } - // 11. src is a slice and dst is a pointer-to-array. + // 11. src is a slice and dst is an array or pointer-to-array. // They must have same element type. - if src.IsSlice() && dst.IsPtr() && dst.Elem().IsArray() && - types.Identical(src.Elem(), dst.Elem().Elem()) { - return ir.OSLICE2ARRPTR, "" + if src.IsSlice() { + if dst.IsArray() && types.Identical(src.Elem(), dst.Elem()) { + return ir.OSLICE2ARR, "" + } + if dst.IsPtr() && dst.Elem().IsArray() && + types.Identical(src.Elem(), dst.Elem().Elem()) { + return ir.OSLICE2ARRPTR, "" + } } return ir.OXXX, "" diff --git a/src/cmd/compile/internal/walk/convert.go b/src/cmd/compile/internal/walk/convert.go index 57f28e9800..c67a29fc09 100644 --- a/src/cmd/compile/internal/walk/convert.go +++ b/src/cmd/compile/internal/walk/convert.go @@ -503,3 +503,21 @@ func walkCheckPtrArithmetic(n *ir.ConvExpr, init *ir.Nodes) ir.Node { return cheap } + +// walkSliceToArray walks an OSLICE2ARR expression. +func walkSliceToArray(n *ir.ConvExpr, init *ir.Nodes) ir.Node { + // Replace T(x) with *(*T)(x). + conv := typecheck.Expr(ir.NewConvExpr(base.Pos, ir.OCONV, types.NewPtr(n.Type()), n.X)).(*ir.ConvExpr) + deref := typecheck.Expr(ir.NewStarExpr(base.Pos, conv)).(*ir.StarExpr) + + // The OSLICE2ARRPTR conversion handles checking the slice length, + // so the dereference can't fail. + // + // However, this is more than just an optimization: if T is a + // zero-length array, then x (and thus (*T)(x)) can be nil, but T(x) + // should *not* panic. So suppressing the nil check here is + // necessary for correctness in that case. + deref.SetBounded(true) + + return walkExpr(deref, init) +} diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go index 2842c53df2..c12fb20106 100644 --- a/src/cmd/compile/internal/walk/expr.go +++ b/src/cmd/compile/internal/walk/expr.go @@ -227,6 +227,10 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node { n := n.(*ir.ConvExpr) return walkConv(n, init) + case ir.OSLICE2ARR: + n := n.(*ir.ConvExpr) + return walkSliceToArray(n, init) + case ir.OSLICE2ARRPTR: n := n.(*ir.ConvExpr) n.X = walkExpr(n.X, init) diff --git a/src/cmd/compile/internal/walk/walk.go b/src/cmd/compile/internal/walk/walk.go index d6b09866f7..f5a2f9b9ac 100644 --- a/src/cmd/compile/internal/walk/walk.go +++ b/src/cmd/compile/internal/walk/walk.go @@ -312,7 +312,8 @@ func mayCall(n ir.Node) bool { return true case ir.OINDEX, ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR, ir.OSLICESTR, - ir.ODEREF, ir.ODOTPTR, ir.ODOTTYPE, ir.ODYNAMICDOTTYPE, ir.ODIV, ir.OMOD, ir.OSLICE2ARRPTR: + ir.ODEREF, ir.ODOTPTR, ir.ODOTTYPE, ir.ODYNAMICDOTTYPE, ir.ODIV, ir.OMOD, + ir.OSLICE2ARR, ir.OSLICE2ARRPTR: // These ops might panic, make sure they are done // before we start marshaling args for a call. See issue 16760. return true diff --git a/src/runtime/error.go b/src/runtime/error.go index b11473c634..a211fbf515 100644 --- a/src/runtime/error.go +++ b/src/runtime/error.go @@ -151,7 +151,7 @@ var boundsErrorFmts = [...]string{ boundsSlice3Acap: "slice bounds out of range [::%x] with capacity %y", boundsSlice3B: "slice bounds out of range [:%x:%y]", boundsSlice3C: "slice bounds out of range [%x:%y:]", - boundsConvert: "cannot convert slice with length %y to pointer to array with length %x", + boundsConvert: "cannot convert slice with length %y to array or pointer to array with length %x", } // boundsNegErrorFmts are overriding formats if x is negative. In this case there's no need to report y. diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 92ef96882f..26618db7ce 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -197,9 +197,9 @@ func goPanicSlice3CU(x uint, y int) { panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3C}) } -// failures in the conversion (*[x]T)s, 0 <= x <= y, x == cap(s) +// failures in the conversion ([x]T)(s) or (*[x]T)(s), 0 <= x <= y, y == len(s) func goPanicSliceConvert(x int, y int) { - panicCheck1(getcallerpc(), "slice length too short to convert to pointer to array") + panicCheck1(getcallerpc(), "slice length too short to convert to array or pointer to array") panic(boundsError{x: int64(x), signed: true, y: y, code: boundsConvert}) } diff --git a/test/convert4.go b/test/convert4.go index 2bc9c96a52..3cc0aea7be 100644 --- a/test/convert4.go +++ b/test/convert4.go @@ -23,25 +23,47 @@ func wantPanic(fn func(), s string) { func main() { s := make([]byte, 8, 10) + for i := range s { + s[i] = byte(i) + } if p := (*[8]byte)(s); &p[0] != &s[0] { panic("*[8]byte conversion failed") } + if [8]byte(s) != *(*[8]byte)(s) { + panic("[8]byte conversion failed") + } wantPanic( func() { _ = (*[9]byte)(s) }, - "runtime error: cannot convert slice with length 8 to pointer to array with length 9", + "runtime error: cannot convert slice with length 8 to array or pointer to array with length 9", + ) + wantPanic( + func() { + _ = [9]byte(s) + }, + "runtime error: cannot convert slice with length 8 to array or pointer to array with length 9", ) var n []byte if p := (*[0]byte)(n); p != nil { panic("nil slice converted to *[0]byte should be nil") } + _ = [0]byte(n) z := make([]byte, 0) if p := (*[0]byte)(z); p == nil { panic("empty slice converted to *[0]byte should be non-nil") } + _ = [0]byte(z) + + var p *[]byte + wantPanic( + func() { + _ = [0]byte(*p) // evaluating *p should still panic + }, + "runtime error: invalid memory address or nil pointer dereference", + ) // Test with named types type Slice []int diff --git a/test/escape_slice.go b/test/escape_slice.go index 055b60be41..7f94a755b9 100644 --- a/test/escape_slice.go +++ b/test/escape_slice.go @@ -105,6 +105,10 @@ func slice12(x []int) *[1]int { // ERROR "leaking param: x to result ~r0 level=0 return (*[1]int)(x) } +func slice13(x []*int) [1]*int { // ERROR "leaking param: x to result ~r0 level=1$" + return [1]*int(x) +} + func envForDir(dir string) []string { // ERROR "dir does not escape" env := os.Environ() return mergeEnvLists([]string{"PWD=" + dir}, env) // ERROR ".PWD=. \+ dir escapes to heap" "\[\]string{...} does not escape"