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>
This commit is contained in:
Cuong Manh Le 2021-07-01 02:13:28 +07:00
parent f0847e0ce9
commit 20dafe5d60
4 changed files with 60 additions and 3 deletions

View File

@ -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)
}
}

View File

@ -168,7 +168,7 @@ func isValuePreserving(ut_src, ut_dst types.Type) bool {
// 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 @@ func emitConv(f *Function, val Value, typ types.Type) Value {
// 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.)

View File

@ -133,6 +133,13 @@ func (s *sanity) checkInstr(idx int, instr Instruction) {
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())

View File

@ -615,10 +615,9 @@ type ChangeType struct {
// - 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.
//