From 20dafe5d6055a2382de349face79f568e574d9fd Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Thu, 1 Jul 2021 02:13:28 +0700 Subject: [PATCH] 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 Run-TryBot: Cuong Manh Le gopls-CI: kokoro TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- go/ssa/builder_go117_test.go | 41 ++++++++++++++++++++++++++++++++++++ go/ssa/emit.go | 12 ++++++++++- go/ssa/sanity.go | 7 ++++++ go/ssa/ssa.go | 3 +-- 4 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 go/ssa/builder_go117_test.go diff --git a/go/ssa/builder_go117_test.go b/go/ssa/builder_go117_test.go new file mode 100644 index 0000000000..93316c1f52 --- /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 13fe2aa9c1..df9ca4ff0f 100644 --- a/go/ssa/emit.go +++ b/go/ssa/emit.go @@ -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.) diff --git a/go/ssa/sanity.go b/go/ssa/sanity.go index 0a7abc5e98..16df7e4f0c 100644 --- a/go/ssa/sanity.go +++ b/go/ssa/sanity.go @@ -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()) diff --git a/go/ssa/ssa.go b/go/ssa/ssa.go index 4dfdafdb22..c604272c36 100644 --- a/go/ssa/ssa.go +++ b/go/ssa/ssa.go @@ -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. //