]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: fix conv of slice of user-define byte type to string
authorDan Scales <danscales@google.com>
Thu, 6 Jan 2022 20:39:37 +0000 (12:39 -0800)
committerDan Scales <danscales@google.com>
Fri, 7 Jan 2022 18:40:16 +0000 (18:40 +0000)
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 <mdempsky@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/cmd/compile/internal/noder/transform.go
src/cmd/compile/internal/typecheck/expr.go
test/fixedbugs/issue23536.go [new file with mode: 0644]
test/typeparam/issue23536.go [new file with mode: 0644]

index a673484821b0c2161f2e5eb7e2a13136c5b8c12d..6f49106f5e4e3dfc11cdad25dae65465576be77b 100644 (file)
@@ -115,6 +115,31 @@ func transformConv(n *ir.ConvExpr) ir.Node {
                if n.X.Op() == ir.OLITERAL {
                        return stringtoruneslit(n)
                }
+
+       case ir.OBYTES2STR:
+               assert(t.IsSlice())
+               assert(t.Elem().Kind() == types.TUINT8)
+               if t.Elem() != types.ByteType && t.Elem() != types.Types[types.TUINT8] {
+                       // If t is a slice of a user-defined byte type B (not uint8
+                       // or byte), then add an extra CONVNOP from []B to []byte, so
+                       // that the call to slicebytetostring() added in walk will
+                       // typecheck correctly.
+                       n.X = ir.NewConvExpr(n.X.Pos(), ir.OCONVNOP, types.NewSlice(types.ByteType), n.X)
+                       n.X.SetTypecheck(1)
+               }
+
+       case ir.ORUNES2STR:
+               assert(t.IsSlice())
+               assert(t.Elem().Kind() == types.TINT32)
+               if t.Elem() != types.RuneType && t.Elem() != types.Types[types.TINT32] {
+                       // If t is a slice of a user-defined rune type B (not uint32
+                       // or rune), then add an extra CONVNOP from []B to []rune, so
+                       // that the call to slicerunetostring() added in walk will
+                       // typecheck correctly.
+                       n.X = ir.NewConvExpr(n.X.Pos(), ir.OCONVNOP, types.NewSlice(types.RuneType), n.X)
+                       n.X.SetTypecheck(1)
+               }
+
        }
        return n
 }
index 9b74bf7a9d3762ce60c7fbc414fc9e2770885fcd..eb316d33db26dd1860e2031fd05d348b7e5e8416 100644 (file)
@@ -466,6 +466,27 @@ func tcConv(n *ir.ConvExpr) ir.Node {
                if n.X.Op() == ir.OLITERAL {
                        return stringtoruneslit(n)
                }
+
+       case ir.OBYTES2STR:
+               if t.Elem() != types.ByteType && t.Elem() != types.Types[types.TUINT8] {
+                       // If t is a slice of a user-defined byte type B (not uint8
+                       // or byte), then add an extra CONVNOP from []B to []byte, so
+                       // that the call to slicebytetostring() added in walk will
+                       // typecheck correctly.
+                       n.X = ir.NewConvExpr(n.X.Pos(), ir.OCONVNOP, types.NewSlice(types.ByteType), n.X)
+                       n.X.SetTypecheck(1)
+               }
+
+       case ir.ORUNES2STR:
+               if t.Elem() != types.RuneType && t.Elem() != types.Types[types.TINT32] {
+                       // If t is a slice of a user-defined rune type B (not uint32
+                       // or rune), then add an extra CONVNOP from []B to []rune, so
+                       // that the call to slicerunetostring() added in walk will
+                       // typecheck correctly.
+                       n.X = ir.NewConvExpr(n.X.Pos(), ir.OCONVNOP, types.NewSlice(types.RuneType), n.X)
+                       n.X.SetTypecheck(1)
+               }
+
        }
        return n
 }
diff --git a/test/fixedbugs/issue23536.go b/test/fixedbugs/issue23536.go
new file mode 100644 (file)
index 0000000..07b5033
--- /dev/null
@@ -0,0 +1,22 @@
+// run
+
+// Copyright 2022 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.
+
+// Test case where a slice of a user-defined byte type (not uint8 or byte) is
+// converted to a string.  Same for slice of runes.
+
+package main
+
+type MyByte byte
+
+type MyRune rune
+
+func main() {
+       var y []MyByte
+       _ = string(y)
+
+       var z []MyRune
+       _ = string(z)
+}
diff --git a/test/typeparam/issue23536.go b/test/typeparam/issue23536.go
new file mode 100644 (file)
index 0000000..a4f0618
--- /dev/null
@@ -0,0 +1,32 @@
+// run -gcflags=-G=3
+
+// Copyright 2022 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.
+
+// Test case where a slice of a user-defined byte type (not uint8 or byte) is
+// converted to a string.  Same for slice of runes.
+
+package main
+
+type MyByte byte
+
+type MyRune rune
+
+func f[T []MyByte](x T) string {
+       return string(x)
+}
+
+func g[T []MyRune](x T) string {
+       return string(x)
+}
+
+func main() {
+       var y []MyByte
+       _ = f(y)
+       _ = string(y)
+
+       var z []MyRune
+       _ = g(z)
+       _ = string(z)
+}