mirror of
https://github.com/golang/go
synced 2024-11-05 18:36:08 +00:00
go/types, types2: add more tests for unsafe.Slice/SliceData/String/StringData
Also: - fine-tune the implementation for some of the new builtin functions - make sure the go/types code is an exact as possible copy of the types2 code - fix the description and examples for errorcodes.go Follow-up on CL 423754. For #53003. Change-Id: I5c70b74e90c724cf6c842cedc6f8ace26fde372b Reviewed-on: https://go-review.googlesource.com/c/go/+/425454 Reviewed-by: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Robert Griesemer <gri@google.com>
This commit is contained in:
parent
ba5deb408f
commit
8c8429fe41
7 changed files with 143 additions and 39 deletions
|
@ -757,7 +757,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
|||
}
|
||||
|
||||
x.mode = value
|
||||
x.typ = NewPointer(slice.Elem())
|
||||
x.typ = NewPointer(slice.elem)
|
||||
if check.Types != nil {
|
||||
check.recordBuiltinType(call.Fun, makeSig(x.typ, slice))
|
||||
}
|
||||
|
@ -793,16 +793,15 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
|||
return
|
||||
}
|
||||
|
||||
str, _ := x.typ.(*Basic)
|
||||
if str == nil || str.Kind() != String {
|
||||
check.errorf(x, invalidArg+"%s is not a string", x)
|
||||
check.assignment(x, Typ[String], "argument to unsafe.StringData")
|
||||
if x.mode == invalid {
|
||||
return
|
||||
}
|
||||
|
||||
x.mode = value
|
||||
x.typ = NewPointer(universeByte)
|
||||
if check.Types != nil {
|
||||
check.recordBuiltinType(call.Fun, makeSig(x.typ, str))
|
||||
check.recordBuiltinType(call.Fun, makeSig(x.typ, Typ[String]))
|
||||
}
|
||||
|
||||
case _Assert:
|
||||
|
|
|
@ -128,15 +128,16 @@ var builtinCalls = []struct {
|
|||
|
||||
{"Slice", `var p *int; _ = unsafe.Slice(p, 1)`, `func(*int, int) []int`},
|
||||
{"Slice", `var p *byte; var n uintptr; _ = unsafe.Slice(p, n)`, `func(*byte, uintptr) []byte`},
|
||||
{"Slice", `type B *byte; var b B; _ = unsafe.Slice(b, 0)`, `func(*byte, int) []byte`},
|
||||
|
||||
{"SliceData", "var a []int; _ = unsafe.SliceData(a)", `func([]int) *int`},
|
||||
{"SliceData", "type sliceType []int; var a sliceType; _ = unsafe.SliceData(a)", `func([]int) *int`},
|
||||
{"SliceData", "var s []int; _ = unsafe.SliceData(s)", `func([]int) *int`},
|
||||
{"SliceData", "type S []int; var s S; _ = unsafe.SliceData(s)", `func([]int) *int`},
|
||||
|
||||
{"String", `var p *byte; _ = unsafe.String(p, 1)`, `func(*byte, int) string`},
|
||||
{"String", `type pbyte *byte; var p pbyte; var n uintptr; _ = unsafe.String(p, n)`, `func(*byte, uintptr) string`},
|
||||
{"String", `type B *byte; var b B; _ = unsafe.String(b, 0)`, `func(*byte, int) string`},
|
||||
|
||||
{"StringData", `var s string; _ = unsafe.StringData(s)`, `func(string) *byte`},
|
||||
{"StringData", `var s = "abc"; _ = unsafe.StringData(s)`, `func(string) *byte`},
|
||||
{"StringData", `_ = unsafe.StringData("foo")`, `func(string) *byte`},
|
||||
|
||||
{"assert", `assert(true)`, `invalid type`}, // constant
|
||||
{"assert", `type B bool; const pred B = 1 < 2; assert(pred)`, `invalid type`}, // constant
|
||||
|
|
|
@ -849,6 +849,60 @@ func Sizeof2() {
|
|||
_ = unsafe.Sizeof(f2()) // ERROR too many arguments
|
||||
}
|
||||
|
||||
func Slice1() {
|
||||
var x int
|
||||
unsafe.Slice() // ERROR not enough arguments
|
||||
unsafe.Slice(1, 2, 3) // ERROR too many arguments
|
||||
unsafe.Slice(1 /* ERROR is not a pointer */ , 2)
|
||||
unsafe.Slice(nil /* ERROR nil is not a pointer */ , 0)
|
||||
unsafe.Slice(&x, "foo" /* ERROR cannot convert .* to int */ )
|
||||
unsafe.Slice(&x, 1.2 /* ERROR truncated to int */ )
|
||||
unsafe.Slice(&x, - /* ERROR must not be negative */ 1)
|
||||
unsafe /* ERROR not used */ .Slice(&x, 0)
|
||||
var _ []byte = unsafe /* ERROR value of type \[\]int */ .Slice(&x, 0)
|
||||
|
||||
var _ []int = unsafe.Slice(&x, 0)
|
||||
_ = unsafe.Slice(&x, 1.0)
|
||||
_ = unsafe.Slice((*int)(nil), 0)
|
||||
}
|
||||
|
||||
func SliceData1() {
|
||||
var s []int
|
||||
unsafe.SliceData(0 /* ERROR not a slice */)
|
||||
unsafe /* ERROR not used */ .SliceData(s)
|
||||
|
||||
type S []int
|
||||
_ = unsafe.SliceData(s)
|
||||
_ = unsafe.SliceData(S{})
|
||||
}
|
||||
|
||||
func String1() {
|
||||
var b byte
|
||||
unsafe.String() // ERROR not enough arguments
|
||||
unsafe.String(1, 2, 3) // ERROR too many arguments
|
||||
unsafe.String(1 /* ERROR cannot use 1 */ , 2)
|
||||
unsafe.String(&b, "foo" /* ERROR cannot convert .* to int */ )
|
||||
unsafe.String(&b, 1.2 /* ERROR truncated to int */ )
|
||||
unsafe.String(&b, - /* ERROR must not be negative */ 1)
|
||||
unsafe /* ERROR not used */ .String(&b, 0)
|
||||
var _ []byte = unsafe /* ERROR value of type string */ .String(&b, 0)
|
||||
|
||||
var _ string = unsafe.String(&b, 0)
|
||||
_ = unsafe.String(&b, 1.0)
|
||||
_ = unsafe.String(nil, 0) // here we allow nil as ptr argument (in contrast to unsafe.Slice)
|
||||
}
|
||||
|
||||
func StringData1() {
|
||||
var s string
|
||||
type S string
|
||||
unsafe.StringData(0 /* ERROR cannot use 0 */)
|
||||
unsafe.StringData(S /* ERROR cannot use S */ ("foo"))
|
||||
unsafe /* ERROR not used */ .StringData(s)
|
||||
|
||||
_ = unsafe.StringData(s)
|
||||
_ = unsafe.StringData("foo")
|
||||
}
|
||||
|
||||
// self-testing only
|
||||
func assert1() {
|
||||
var x int
|
||||
|
|
|
@ -753,19 +753,20 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
}
|
||||
|
||||
case _SliceData:
|
||||
// unsafe.SliceData(str string) *byte
|
||||
// unsafe.SliceData(slice []T) *T
|
||||
if !check.allowVersion(check.pkg, 1, 20) {
|
||||
check.errorf(call.Fun, _InvalidUnsafeSliceData, "unsafe.SliceData requires go1.20 or later")
|
||||
return
|
||||
}
|
||||
|
||||
slice, ok := under(x.typ).(*Slice)
|
||||
if !ok {
|
||||
slice, _ := under(x.typ).(*Slice) // TODO(gri) should this be coreType rather than under?
|
||||
if slice == nil {
|
||||
check.invalidArg(x, _InvalidUnsafeSliceData, "%s is not a slice", x)
|
||||
return
|
||||
}
|
||||
|
||||
x.mode = value
|
||||
x.typ = NewPointer(slice.Elem())
|
||||
x.typ = NewPointer(slice.elem)
|
||||
if check.Types != nil {
|
||||
check.recordBuiltinType(call.Fun, makeSig(x.typ, slice))
|
||||
}
|
||||
|
@ -779,7 +780,6 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
|
||||
check.assignment(x, NewPointer(universeByte), "argument to unsafe.String")
|
||||
if x.mode == invalid {
|
||||
check.invalidArg(x, _InvalidUnsafeString, "%s is not a *byte", x)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -802,16 +802,15 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
return
|
||||
}
|
||||
|
||||
str, _ := x.typ.(*Basic)
|
||||
if str == nil || str.kind != String {
|
||||
check.invalidArg(x, _InvalidUnsafeStringData, "%s is not a string", x)
|
||||
check.assignment(x, Typ[String], "argument to unsafe.StringData")
|
||||
if x.mode == invalid {
|
||||
return
|
||||
}
|
||||
|
||||
x.mode = value
|
||||
x.typ = NewPointer(universeByte)
|
||||
if check.Types != nil {
|
||||
check.recordBuiltinType(call.Fun, makeSig(x.typ, str))
|
||||
check.recordBuiltinType(call.Fun, makeSig(x.typ, Typ[String]))
|
||||
}
|
||||
|
||||
case _Assert:
|
||||
|
|
|
@ -129,15 +129,16 @@ var builtinCalls = []struct {
|
|||
|
||||
{"Slice", `var p *int; _ = unsafe.Slice(p, 1)`, `func(*int, int) []int`},
|
||||
{"Slice", `var p *byte; var n uintptr; _ = unsafe.Slice(p, n)`, `func(*byte, uintptr) []byte`},
|
||||
{"Slice", `type B *byte; var b B; _ = unsafe.Slice(b, 0)`, `func(*byte, int) []byte`},
|
||||
|
||||
{"SliceData", "var a []int; _ = unsafe.SliceData(a)", `func([]int) *int`},
|
||||
{"SliceData", "type sliceType []int; var a sliceType; _ = unsafe.SliceData(a)", `func([]int) *int`},
|
||||
{"SliceData", "var s []int; _ = unsafe.SliceData(s)", `func([]int) *int`},
|
||||
{"SliceData", "type S []int; var s S; _ = unsafe.SliceData(s)", `func([]int) *int`},
|
||||
|
||||
{"String", `var p *byte; _ = unsafe.String(p, 1)`, `func(*byte, int) string`},
|
||||
{"String", `type pbyte *byte; var p pbyte; var n uintptr; _ = unsafe.String(p, n)`, `func(*byte, uintptr) string`},
|
||||
{"String", `type B *byte; var b B; _ = unsafe.String(b, 0)`, `func(*byte, int) string`},
|
||||
|
||||
{"StringData", `var s string; _ = unsafe.StringData(s)`, `func(string) *byte`},
|
||||
{"StringData", `var s = "abc"; _ = unsafe.StringData(s)`, `func(string) *byte`},
|
||||
{"StringData", `_ = unsafe.StringData("foo")`, `func(string) *byte`},
|
||||
|
||||
{"assert", `assert(true)`, `invalid type`}, // constant
|
||||
{"assert", `type B bool; const pred B = 1 < 2; assert(pred)`, `invalid type`}, // constant
|
||||
|
|
|
@ -1261,6 +1261,8 @@ const (
|
|||
|
||||
// _InvalidUnsafeAdd occurs when unsafe.Add is called with a
|
||||
// length argument that is not of integer type.
|
||||
// It also occurs if it is used in a package compiled for a
|
||||
// language version before go1.17.
|
||||
//
|
||||
// Example:
|
||||
// import "unsafe"
|
||||
|
@ -1272,6 +1274,8 @@ const (
|
|||
// _InvalidUnsafeSlice occurs when unsafe.Slice is called with a
|
||||
// pointer argument that is not of pointer type or a length argument
|
||||
// that is not of integer type, negative, or out of bounds.
|
||||
// It also occurs if it is used in a package compiled for a language
|
||||
// version before go1.17.
|
||||
//
|
||||
// Example:
|
||||
// import "unsafe"
|
||||
|
@ -1390,8 +1394,9 @@ const (
|
|||
// type T[P any] struct{ *P }
|
||||
_MisplacedTypeParam
|
||||
|
||||
// _InvalidUnsafeSliceData occurs when unsafe.SliceData called with type
|
||||
// is not slice
|
||||
// _InvalidUnsafeSliceData occurs when unsafe.SliceData is called with
|
||||
// an argument that is not of slice type. It also occurs if it is used
|
||||
// in a package compiled for a language version before go1.20.
|
||||
//
|
||||
// Example:
|
||||
// import "unsafe"
|
||||
|
@ -1400,9 +1405,10 @@ const (
|
|||
// var _ = unsafe.SliceData(x)
|
||||
_InvalidUnsafeSliceData
|
||||
|
||||
// _InvalidUnsafeString occurs when unsafe.String is called with a
|
||||
// pointer argument that is not of pointer type or a length argument
|
||||
// that is not of integer type, negative, or out of bounds.
|
||||
// _InvalidUnsafeString occurs when unsafe.String is called with
|
||||
// a length argument that is not of integer type, negative, or
|
||||
// out of bounds. It also occurs if it is used in a package
|
||||
// compiled for a language version before go1.20.
|
||||
//
|
||||
// Example:
|
||||
// import "unsafe"
|
||||
|
@ -1411,17 +1417,7 @@ const (
|
|||
// var _ = unsafe.String(&b[0], -1)
|
||||
_InvalidUnsafeString
|
||||
|
||||
// _InvalidUnsafeStringData
|
||||
//
|
||||
// Example:
|
||||
// import "unsafe"
|
||||
//
|
||||
// var x int
|
||||
// var _ = unsafe.StringData(x)
|
||||
//
|
||||
// Example:
|
||||
// import "unsafe"
|
||||
//
|
||||
// var _ = unsafe.StringData("abc")
|
||||
// _InvalidUnsafeStringData occurs if it is used in a package
|
||||
// compiled for a language version before go1.20.
|
||||
_InvalidUnsafeStringData
|
||||
)
|
||||
|
|
54
src/go/types/testdata/check/builtins0.go
vendored
54
src/go/types/testdata/check/builtins0.go
vendored
|
@ -849,6 +849,60 @@ func Sizeof2() {
|
|||
_ = unsafe.Sizeof(f2()) // ERROR too many arguments
|
||||
}
|
||||
|
||||
func Slice1() {
|
||||
var x int
|
||||
unsafe.Slice() // ERROR not enough arguments
|
||||
unsafe.Slice(1, 2, 3) // ERROR too many arguments
|
||||
unsafe.Slice(1 /* ERROR is not a pointer */ , 2)
|
||||
unsafe.Slice(nil /* ERROR nil is not a pointer */ , 0)
|
||||
unsafe.Slice(&x, "foo" /* ERROR cannot convert .* to int */ )
|
||||
unsafe.Slice(&x, 1.2 /* ERROR truncated to int */ )
|
||||
unsafe.Slice(&x, - /* ERROR must not be negative */ 1)
|
||||
unsafe /* ERROR not used */ .Slice(&x, 0)
|
||||
var _ []byte = unsafe /* ERROR value of type \[\]int */ .Slice(&x, 0)
|
||||
|
||||
var _ []int = unsafe.Slice(&x, 0)
|
||||
_ = unsafe.Slice(&x, 1.0)
|
||||
_ = unsafe.Slice((*int)(nil), 0)
|
||||
}
|
||||
|
||||
func SliceData1() {
|
||||
var s []int
|
||||
unsafe.SliceData(0 /* ERROR not a slice */)
|
||||
unsafe /* ERROR not used */ .SliceData(s)
|
||||
|
||||
type S []int
|
||||
_ = unsafe.SliceData(s)
|
||||
_ = unsafe.SliceData(S{})
|
||||
}
|
||||
|
||||
func String1() {
|
||||
var b byte
|
||||
unsafe.String() // ERROR not enough arguments
|
||||
unsafe.String(1, 2, 3) // ERROR too many arguments
|
||||
unsafe.String(1 /* ERROR cannot use 1 */ , 2)
|
||||
unsafe.String(&b, "foo" /* ERROR cannot convert .* to int */ )
|
||||
unsafe.String(&b, 1.2 /* ERROR truncated to int */ )
|
||||
unsafe.String(&b, - /* ERROR must not be negative */ 1)
|
||||
unsafe /* ERROR not used */ .String(&b, 0)
|
||||
var _ []byte = unsafe /* ERROR value of type string */ .String(&b, 0)
|
||||
|
||||
var _ string = unsafe.String(&b, 0)
|
||||
_ = unsafe.String(&b, 1.0)
|
||||
_ = unsafe.String(nil, 0) // here we allow nil as ptr argument (in contrast to unsafe.Slice)
|
||||
}
|
||||
|
||||
func StringData1() {
|
||||
var s string
|
||||
type S string
|
||||
unsafe.StringData(0 /* ERROR cannot use 0 */)
|
||||
unsafe.StringData(S /* ERROR cannot use S */ ("foo"))
|
||||
unsafe /* ERROR not used */ .StringData(s)
|
||||
|
||||
_ = unsafe.StringData(s)
|
||||
_ = unsafe.StringData("foo")
|
||||
}
|
||||
|
||||
// self-testing only
|
||||
func assert1() {
|
||||
var x int
|
||||
|
|
Loading…
Reference in a new issue