mirror of https://github.com/golang/go.git
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:
parent
f0847e0ce9
commit
20dafe5d60
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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.)
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
//
|
||||
|
|
|
|||
Loading…
Reference in New Issue