go/ssa: allow conversion from slice to array pointer
Fixes golang/go#46987
Change-Id: Ic3b4410c3ea9f62d3cdce579a1152884167be16b
Reviewed-on: https://go-review.googlesource.com/c/tools/+/332049
Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
diff --git a/go/ssa/builder_go117_test.go b/go/ssa/builder_go117_test.go
new file mode 100644
index 0000000..93316c1
--- /dev/null
+++ b/go/ssa/builder_go117_test.go
@@ -0,0 +1,41 @@
+// Copyright 2021 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.
+
+//go:build go1.17
+// +build go1.17
+
+package ssa_test
+
+import (
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "go/types"
+ "testing"
+
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/ssa/ssautil"
+)
+
+func TestSliceToArrayPtr(t *testing.T) {
+ src := `package p
+
+func f() {
+ var s []byte
+ _ = (*[4]byte)(s)
+}
+`
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, "p.go", src, parser.ParseComments)
+ if err != nil {
+ t.Fatal(err)
+ }
+ files := []*ast.File{f}
+
+ pkg := types.NewPackage("p", "")
+ conf := &types.Config{}
+ if _, _, err := ssautil.BuildPackage(conf, fset, pkg, files, ssa.SanityCheckFunctions); err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+}
diff --git a/go/ssa/emit.go b/go/ssa/emit.go
index 13fe2aa..df9ca4f 100644
--- a/go/ssa/emit.go
+++ b/go/ssa/emit.go
@@ -168,7 +168,7 @@
// emitConv emits to f code to convert Value val to exactly type typ,
// and returns the converted value. Implicit conversions are required
// by language assignability rules in assignments, parameter passing,
-// etc. Conversions cannot fail dynamically.
+// etc.
//
func emitConv(f *Function, val Value, typ types.Type) Value {
t_src := val.Type()
@@ -228,6 +228,16 @@
// e.g. string -> []byte/[]rune.
}
+ // Conversion from slice to array pointer?
+ if slice, ok := ut_src.(*types.Slice); ok {
+ if ptr, ok := ut_dst.(*types.Pointer); ok {
+ if arr, ok := ptr.Elem().(*types.Array); ok && types.Identical(slice.Elem(), arr.Elem()) {
+ c := &Convert{X: val}
+ c.setType(ut_dst)
+ return f.emit(c)
+ }
+ }
+ }
// A representation-changing conversion?
// At least one of {ut_src,ut_dst} must be *Basic.
// (The other may be []byte or []rune.)
diff --git a/go/ssa/sanity.go b/go/ssa/sanity.go
index 0a7abc5..16df7e4 100644
--- a/go/ssa/sanity.go
+++ b/go/ssa/sanity.go
@@ -133,6 +133,13 @@
case *ChangeInterface:
case *ChangeType:
case *Convert:
+ if _, ok := instr.X.Type().Underlying().(*types.Slice); ok {
+ if ptr, ok := instr.Type().Underlying().(*types.Pointer); ok {
+ if _, ok := ptr.Elem().(*types.Array); ok {
+ break
+ }
+ }
+ }
if _, ok := instr.X.Type().Underlying().(*types.Basic); !ok {
if _, ok := instr.Type().Underlying().(*types.Basic); !ok {
s.errorf("convert %s -> %s: at least one type must be basic", instr.X.Type(), instr.Type())
diff --git a/go/ssa/ssa.go b/go/ssa/ssa.go
index 4dfdafd..c604272 100644
--- a/go/ssa/ssa.go
+++ b/go/ssa/ssa.go
@@ -615,10 +615,9 @@
// - between pointers and unsafe.Pointer.
// - between unsafe.Pointer and uintptr.
// - from (Unicode) integer to (UTF-8) string.
+// - from slice to array pointer.
// A conversion may imply a type name change also.
//
-// This operation cannot fail dynamically.
-//
// Conversions of untyped string/number/bool constants to a specific
// representation are eliminated during SSA construction.
//