Skip to content

Commit 8c8429f

Browse files
committed
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 <[email protected]> Reviewed-by: Robert Griesemer <[email protected]>
1 parent ba5deb4 commit 8c8429f

File tree

7 files changed

+143
-39
lines changed

7 files changed

+143
-39
lines changed

src/cmd/compile/internal/types2/builtins.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
757757
}
758758

759759
x.mode = value
760-
x.typ = NewPointer(slice.Elem())
760+
x.typ = NewPointer(slice.elem)
761761
if check.Types != nil {
762762
check.recordBuiltinType(call.Fun, makeSig(x.typ, slice))
763763
}
@@ -793,16 +793,15 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
793793
return
794794
}
795795

796-
str, _ := x.typ.(*Basic)
797-
if str == nil || str.Kind() != String {
798-
check.errorf(x, invalidArg+"%s is not a string", x)
796+
check.assignment(x, Typ[String], "argument to unsafe.StringData")
797+
if x.mode == invalid {
799798
return
800799
}
801800

802801
x.mode = value
803802
x.typ = NewPointer(universeByte)
804803
if check.Types != nil {
805-
check.recordBuiltinType(call.Fun, makeSig(x.typ, str))
804+
check.recordBuiltinType(call.Fun, makeSig(x.typ, Typ[String]))
806805
}
807806

808807
case _Assert:

src/cmd/compile/internal/types2/builtins_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,16 @@ var builtinCalls = []struct {
128128

129129
{"Slice", `var p *int; _ = unsafe.Slice(p, 1)`, `func(*int, int) []int`},
130130
{"Slice", `var p *byte; var n uintptr; _ = unsafe.Slice(p, n)`, `func(*byte, uintptr) []byte`},
131+
{"Slice", `type B *byte; var b B; _ = unsafe.Slice(b, 0)`, `func(*byte, int) []byte`},
131132

132-
{"SliceData", "var a []int; _ = unsafe.SliceData(a)", `func([]int) *int`},
133-
{"SliceData", "type sliceType []int; var a sliceType; _ = unsafe.SliceData(a)", `func([]int) *int`},
133+
{"SliceData", "var s []int; _ = unsafe.SliceData(s)", `func([]int) *int`},
134+
{"SliceData", "type S []int; var s S; _ = unsafe.SliceData(s)", `func([]int) *int`},
134135

135136
{"String", `var p *byte; _ = unsafe.String(p, 1)`, `func(*byte, int) string`},
136-
{"String", `type pbyte *byte; var p pbyte; var n uintptr; _ = unsafe.String(p, n)`, `func(*byte, uintptr) string`},
137+
{"String", `type B *byte; var b B; _ = unsafe.String(b, 0)`, `func(*byte, int) string`},
137138

138139
{"StringData", `var s string; _ = unsafe.StringData(s)`, `func(string) *byte`},
139-
{"StringData", `var s = "abc"; _ = unsafe.StringData(s)`, `func(string) *byte`},
140+
{"StringData", `_ = unsafe.StringData("foo")`, `func(string) *byte`},
140141

141142
{"assert", `assert(true)`, `invalid type`}, // constant
142143
{"assert", `type B bool; const pred B = 1 < 2; assert(pred)`, `invalid type`}, // constant

src/cmd/compile/internal/types2/testdata/check/builtins0.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,60 @@ func Sizeof2() {
849849
_ = unsafe.Sizeof(f2()) // ERROR too many arguments
850850
}
851851

852+
func Slice1() {
853+
var x int
854+
unsafe.Slice() // ERROR not enough arguments
855+
unsafe.Slice(1, 2, 3) // ERROR too many arguments
856+
unsafe.Slice(1 /* ERROR is not a pointer */ , 2)
857+
unsafe.Slice(nil /* ERROR nil is not a pointer */ , 0)
858+
unsafe.Slice(&x, "foo" /* ERROR cannot convert .* to int */ )
859+
unsafe.Slice(&x, 1.2 /* ERROR truncated to int */ )
860+
unsafe.Slice(&x, - /* ERROR must not be negative */ 1)
861+
unsafe /* ERROR not used */ .Slice(&x, 0)
862+
var _ []byte = unsafe /* ERROR value of type \[\]int */ .Slice(&x, 0)
863+
864+
var _ []int = unsafe.Slice(&x, 0)
865+
_ = unsafe.Slice(&x, 1.0)
866+
_ = unsafe.Slice((*int)(nil), 0)
867+
}
868+
869+
func SliceData1() {
870+
var s []int
871+
unsafe.SliceData(0 /* ERROR not a slice */)
872+
unsafe /* ERROR not used */ .SliceData(s)
873+
874+
type S []int
875+
_ = unsafe.SliceData(s)
876+
_ = unsafe.SliceData(S{})
877+
}
878+
879+
func String1() {
880+
var b byte
881+
unsafe.String() // ERROR not enough arguments
882+
unsafe.String(1, 2, 3) // ERROR too many arguments
883+
unsafe.String(1 /* ERROR cannot use 1 */ , 2)
884+
unsafe.String(&b, "foo" /* ERROR cannot convert .* to int */ )
885+
unsafe.String(&b, 1.2 /* ERROR truncated to int */ )
886+
unsafe.String(&b, - /* ERROR must not be negative */ 1)
887+
unsafe /* ERROR not used */ .String(&b, 0)
888+
var _ []byte = unsafe /* ERROR value of type string */ .String(&b, 0)
889+
890+
var _ string = unsafe.String(&b, 0)
891+
_ = unsafe.String(&b, 1.0)
892+
_ = unsafe.String(nil, 0) // here we allow nil as ptr argument (in contrast to unsafe.Slice)
893+
}
894+
895+
func StringData1() {
896+
var s string
897+
type S string
898+
unsafe.StringData(0 /* ERROR cannot use 0 */)
899+
unsafe.StringData(S /* ERROR cannot use S */ ("foo"))
900+
unsafe /* ERROR not used */ .StringData(s)
901+
902+
_ = unsafe.StringData(s)
903+
_ = unsafe.StringData("foo")
904+
}
905+
852906
// self-testing only
853907
func assert1() {
854908
var x int

src/go/types/builtins.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -753,19 +753,20 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
753753
}
754754

755755
case _SliceData:
756-
// unsafe.SliceData(str string) *byte
756+
// unsafe.SliceData(slice []T) *T
757757
if !check.allowVersion(check.pkg, 1, 20) {
758758
check.errorf(call.Fun, _InvalidUnsafeSliceData, "unsafe.SliceData requires go1.20 or later")
759759
return
760760
}
761761

762-
slice, ok := under(x.typ).(*Slice)
763-
if !ok {
762+
slice, _ := under(x.typ).(*Slice) // TODO(gri) should this be coreType rather than under?
763+
if slice == nil {
764764
check.invalidArg(x, _InvalidUnsafeSliceData, "%s is not a slice", x)
765765
return
766766
}
767+
767768
x.mode = value
768-
x.typ = NewPointer(slice.Elem())
769+
x.typ = NewPointer(slice.elem)
769770
if check.Types != nil {
770771
check.recordBuiltinType(call.Fun, makeSig(x.typ, slice))
771772
}
@@ -779,7 +780,6 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
779780

780781
check.assignment(x, NewPointer(universeByte), "argument to unsafe.String")
781782
if x.mode == invalid {
782-
check.invalidArg(x, _InvalidUnsafeString, "%s is not a *byte", x)
783783
return
784784
}
785785

@@ -802,16 +802,15 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
802802
return
803803
}
804804

805-
str, _ := x.typ.(*Basic)
806-
if str == nil || str.kind != String {
807-
check.invalidArg(x, _InvalidUnsafeStringData, "%s is not a string", x)
805+
check.assignment(x, Typ[String], "argument to unsafe.StringData")
806+
if x.mode == invalid {
808807
return
809808
}
810809

811810
x.mode = value
812811
x.typ = NewPointer(universeByte)
813812
if check.Types != nil {
814-
check.recordBuiltinType(call.Fun, makeSig(x.typ, str))
813+
check.recordBuiltinType(call.Fun, makeSig(x.typ, Typ[String]))
815814
}
816815

817816
case _Assert:

src/go/types/builtins_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,15 +129,16 @@ var builtinCalls = []struct {
129129

130130
{"Slice", `var p *int; _ = unsafe.Slice(p, 1)`, `func(*int, int) []int`},
131131
{"Slice", `var p *byte; var n uintptr; _ = unsafe.Slice(p, n)`, `func(*byte, uintptr) []byte`},
132+
{"Slice", `type B *byte; var b B; _ = unsafe.Slice(b, 0)`, `func(*byte, int) []byte`},
132133

133-
{"SliceData", "var a []int; _ = unsafe.SliceData(a)", `func([]int) *int`},
134-
{"SliceData", "type sliceType []int; var a sliceType; _ = unsafe.SliceData(a)", `func([]int) *int`},
134+
{"SliceData", "var s []int; _ = unsafe.SliceData(s)", `func([]int) *int`},
135+
{"SliceData", "type S []int; var s S; _ = unsafe.SliceData(s)", `func([]int) *int`},
135136

136137
{"String", `var p *byte; _ = unsafe.String(p, 1)`, `func(*byte, int) string`},
137-
{"String", `type pbyte *byte; var p pbyte; var n uintptr; _ = unsafe.String(p, n)`, `func(*byte, uintptr) string`},
138+
{"String", `type B *byte; var b B; _ = unsafe.String(b, 0)`, `func(*byte, int) string`},
138139

139140
{"StringData", `var s string; _ = unsafe.StringData(s)`, `func(string) *byte`},
140-
{"StringData", `var s = "abc"; _ = unsafe.StringData(s)`, `func(string) *byte`},
141+
{"StringData", `_ = unsafe.StringData("foo")`, `func(string) *byte`},
141142

142143
{"assert", `assert(true)`, `invalid type`}, // constant
143144
{"assert", `type B bool; const pred B = 1 < 2; assert(pred)`, `invalid type`}, // constant

src/go/types/errorcodes.go

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,8 @@ const (
12611261

12621262
// _InvalidUnsafeAdd occurs when unsafe.Add is called with a
12631263
// length argument that is not of integer type.
1264+
// It also occurs if it is used in a package compiled for a
1265+
// language version before go1.17.
12641266
//
12651267
// Example:
12661268
// import "unsafe"
@@ -1272,6 +1274,8 @@ const (
12721274
// _InvalidUnsafeSlice occurs when unsafe.Slice is called with a
12731275
// pointer argument that is not of pointer type or a length argument
12741276
// that is not of integer type, negative, or out of bounds.
1277+
// It also occurs if it is used in a package compiled for a language
1278+
// version before go1.17.
12751279
//
12761280
// Example:
12771281
// import "unsafe"
@@ -1390,8 +1394,9 @@ const (
13901394
// type T[P any] struct{ *P }
13911395
_MisplacedTypeParam
13921396

1393-
// _InvalidUnsafeSliceData occurs when unsafe.SliceData called with type
1394-
// is not slice
1397+
// _InvalidUnsafeSliceData occurs when unsafe.SliceData is called with
1398+
// an argument that is not of slice type. It also occurs if it is used
1399+
// in a package compiled for a language version before go1.20.
13951400
//
13961401
// Example:
13971402
// import "unsafe"
@@ -1400,9 +1405,10 @@ const (
14001405
// var _ = unsafe.SliceData(x)
14011406
_InvalidUnsafeSliceData
14021407

1403-
// _InvalidUnsafeString occurs when unsafe.String is called with a
1404-
// pointer argument that is not of pointer type or a length argument
1405-
// that is not of integer type, negative, or out of bounds.
1408+
// _InvalidUnsafeString occurs when unsafe.String is called with
1409+
// a length argument that is not of integer type, negative, or
1410+
// out of bounds. It also occurs if it is used in a package
1411+
// compiled for a language version before go1.20.
14061412
//
14071413
// Example:
14081414
// import "unsafe"
@@ -1411,17 +1417,7 @@ const (
14111417
// var _ = unsafe.String(&b[0], -1)
14121418
_InvalidUnsafeString
14131419

1414-
// _InvalidUnsafeStringData
1415-
//
1416-
// Example:
1417-
// import "unsafe"
1418-
//
1419-
// var x int
1420-
// var _ = unsafe.StringData(x)
1421-
//
1422-
// Example:
1423-
// import "unsafe"
1424-
//
1425-
// var _ = unsafe.StringData("abc")
1420+
// _InvalidUnsafeStringData occurs if it is used in a package
1421+
// compiled for a language version before go1.20.
14261422
_InvalidUnsafeStringData
14271423
)

src/go/types/testdata/check/builtins0.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,60 @@ func Sizeof2() {
849849
_ = unsafe.Sizeof(f2()) // ERROR too many arguments
850850
}
851851

852+
func Slice1() {
853+
var x int
854+
unsafe.Slice() // ERROR not enough arguments
855+
unsafe.Slice(1, 2, 3) // ERROR too many arguments
856+
unsafe.Slice(1 /* ERROR is not a pointer */ , 2)
857+
unsafe.Slice(nil /* ERROR nil is not a pointer */ , 0)
858+
unsafe.Slice(&x, "foo" /* ERROR cannot convert .* to int */ )
859+
unsafe.Slice(&x, 1.2 /* ERROR truncated to int */ )
860+
unsafe.Slice(&x, - /* ERROR must not be negative */ 1)
861+
unsafe /* ERROR not used */ .Slice(&x, 0)
862+
var _ []byte = unsafe /* ERROR value of type \[\]int */ .Slice(&x, 0)
863+
864+
var _ []int = unsafe.Slice(&x, 0)
865+
_ = unsafe.Slice(&x, 1.0)
866+
_ = unsafe.Slice((*int)(nil), 0)
867+
}
868+
869+
func SliceData1() {
870+
var s []int
871+
unsafe.SliceData(0 /* ERROR not a slice */)
872+
unsafe /* ERROR not used */ .SliceData(s)
873+
874+
type S []int
875+
_ = unsafe.SliceData(s)
876+
_ = unsafe.SliceData(S{})
877+
}
878+
879+
func String1() {
880+
var b byte
881+
unsafe.String() // ERROR not enough arguments
882+
unsafe.String(1, 2, 3) // ERROR too many arguments
883+
unsafe.String(1 /* ERROR cannot use 1 */ , 2)
884+
unsafe.String(&b, "foo" /* ERROR cannot convert .* to int */ )
885+
unsafe.String(&b, 1.2 /* ERROR truncated to int */ )
886+
unsafe.String(&b, - /* ERROR must not be negative */ 1)
887+
unsafe /* ERROR not used */ .String(&b, 0)
888+
var _ []byte = unsafe /* ERROR value of type string */ .String(&b, 0)
889+
890+
var _ string = unsafe.String(&b, 0)
891+
_ = unsafe.String(&b, 1.0)
892+
_ = unsafe.String(nil, 0) // here we allow nil as ptr argument (in contrast to unsafe.Slice)
893+
}
894+
895+
func StringData1() {
896+
var s string
897+
type S string
898+
unsafe.StringData(0 /* ERROR cannot use 0 */)
899+
unsafe.StringData(S /* ERROR cannot use S */ ("foo"))
900+
unsafe /* ERROR not used */ .StringData(s)
901+
902+
_ = unsafe.StringData(s)
903+
_ = unsafe.StringData("foo")
904+
}
905+
852906
// self-testing only
853907
func assert1() {
854908
var x int

0 commit comments

Comments
 (0)