Skip to content

Commit f1596d7

Browse files
committed
cmd/compile: fix conv of slice of user-define byte type to string
types2 allows the conversion of a slice of a user-defined byte type B (not builtin uint8 or byte) to string. But runtime.slicebytetostring requires a []byte argument, so add in a CONVNOP from []B to []byte if needed. Same for the conversion of a slice of user-defined rune types to string. I made the same change in the transformations of the old typechecker, so as to keep tcConv() and transformConv() in sync. That fixes the bug for -G=0 mode as well. Fixes #23536 Change-Id: Ic79364427f27489187f3f8015bdfbf0769a70d69 Reviewed-on: https://go-review.googlesource.com/c/go/+/376056 Reviewed-by: Matthew Dempsky <[email protected]> Reviewed-by: Cuong Manh Le <[email protected]> Reviewed-by: Keith Randall <[email protected]> Trust: Dan Scales <[email protected]> Run-TryBot: Dan Scales <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent ade5488 commit f1596d7

File tree

4 files changed

+100
-0
lines changed

4 files changed

+100
-0
lines changed

src/cmd/compile/internal/noder/transform.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,31 @@ func transformConv(n *ir.ConvExpr) ir.Node {
115115
if n.X.Op() == ir.OLITERAL {
116116
return stringtoruneslit(n)
117117
}
118+
119+
case ir.OBYTES2STR:
120+
assert(t.IsSlice())
121+
assert(t.Elem().Kind() == types.TUINT8)
122+
if t.Elem() != types.ByteType && t.Elem() != types.Types[types.TUINT8] {
123+
// If t is a slice of a user-defined byte type B (not uint8
124+
// or byte), then add an extra CONVNOP from []B to []byte, so
125+
// that the call to slicebytetostring() added in walk will
126+
// typecheck correctly.
127+
n.X = ir.NewConvExpr(n.X.Pos(), ir.OCONVNOP, types.NewSlice(types.ByteType), n.X)
128+
n.X.SetTypecheck(1)
129+
}
130+
131+
case ir.ORUNES2STR:
132+
assert(t.IsSlice())
133+
assert(t.Elem().Kind() == types.TINT32)
134+
if t.Elem() != types.RuneType && t.Elem() != types.Types[types.TINT32] {
135+
// If t is a slice of a user-defined rune type B (not uint32
136+
// or rune), then add an extra CONVNOP from []B to []rune, so
137+
// that the call to slicerunetostring() added in walk will
138+
// typecheck correctly.
139+
n.X = ir.NewConvExpr(n.X.Pos(), ir.OCONVNOP, types.NewSlice(types.RuneType), n.X)
140+
n.X.SetTypecheck(1)
141+
}
142+
118143
}
119144
return n
120145
}

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,27 @@ func tcConv(n *ir.ConvExpr) ir.Node {
466466
if n.X.Op() == ir.OLITERAL {
467467
return stringtoruneslit(n)
468468
}
469+
470+
case ir.OBYTES2STR:
471+
if t.Elem() != types.ByteType && t.Elem() != types.Types[types.TUINT8] {
472+
// If t is a slice of a user-defined byte type B (not uint8
473+
// or byte), then add an extra CONVNOP from []B to []byte, so
474+
// that the call to slicebytetostring() added in walk will
475+
// typecheck correctly.
476+
n.X = ir.NewConvExpr(n.X.Pos(), ir.OCONVNOP, types.NewSlice(types.ByteType), n.X)
477+
n.X.SetTypecheck(1)
478+
}
479+
480+
case ir.ORUNES2STR:
481+
if t.Elem() != types.RuneType && t.Elem() != types.Types[types.TINT32] {
482+
// If t is a slice of a user-defined rune type B (not uint32
483+
// or rune), then add an extra CONVNOP from []B to []rune, so
484+
// that the call to slicerunetostring() added in walk will
485+
// typecheck correctly.
486+
n.X = ir.NewConvExpr(n.X.Pos(), ir.OCONVNOP, types.NewSlice(types.RuneType), n.X)
487+
n.X.SetTypecheck(1)
488+
}
489+
469490
}
470491
return n
471492
}

test/fixedbugs/issue23536.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// run
2+
3+
// Copyright 2022 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+
// Test case where a slice of a user-defined byte type (not uint8 or byte) is
8+
// converted to a string. Same for slice of runes.
9+
10+
package main
11+
12+
type MyByte byte
13+
14+
type MyRune rune
15+
16+
func main() {
17+
var y []MyByte
18+
_ = string(y)
19+
20+
var z []MyRune
21+
_ = string(z)
22+
}

test/typeparam/issue23536.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// run -gcflags=-G=3
2+
3+
// Copyright 2022 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+
// Test case where a slice of a user-defined byte type (not uint8 or byte) is
8+
// converted to a string. Same for slice of runes.
9+
10+
package main
11+
12+
type MyByte byte
13+
14+
type MyRune rune
15+
16+
func f[T []MyByte](x T) string {
17+
return string(x)
18+
}
19+
20+
func g[T []MyRune](x T) string {
21+
return string(x)
22+
}
23+
24+
func main() {
25+
var y []MyByte
26+
_ = f(y)
27+
_ = string(y)
28+
29+
var z []MyRune
30+
_ = g(z)
31+
_ = string(z)
32+
}

0 commit comments

Comments
 (0)