return
}
- typ, _ := under(x.typ).(*Pointer)
- if typ == nil {
+ ptr, _ := under(x.typ).(*Pointer) // TODO(gri) should this be coreType rather than under?
+ if ptr == nil {
check.errorf(x, invalidArg+"%s is not a pointer", x)
return
}
}
x.mode = value
- x.typ = NewSlice(typ.base)
+ x.typ = NewSlice(ptr.base)
if check.Types != nil {
- check.recordBuiltinType(call.Fun, makeSig(x.typ, typ, y.typ))
+ check.recordBuiltinType(call.Fun, makeSig(x.typ, ptr, y.typ))
+ }
+
+ case _SliceData:
+ // unsafe.SliceData(slice []T) *T
+ if !check.allowVersion(check.pkg, 1, 20) {
+ check.versionErrorf(call.Fun, "go1.20", "unsafe.SliceData")
+ return
+ }
+
+ slice, _ := under(x.typ).(*Slice) // TODO(gri) should this be coreType rather than under?
+ if slice == nil {
+ check.errorf(x, invalidArg+"%s is not a slice", x)
+ return
+ }
+
+ x.mode = value
+ x.typ = NewPointer(slice.Elem())
+ if check.Types != nil {
+ check.recordBuiltinType(call.Fun, makeSig(x.typ, slice))
+ }
+
+ case _String:
+ // unsafe.String(ptr *byte, len IntegerType) string
+ if !check.allowVersion(check.pkg, 1, 20) {
+ check.versionErrorf(call.Fun, "go1.20", "unsafe.String")
+ return
+ }
+
+ check.assignment(x, NewPointer(universeByte), "argument to unsafe.String")
+ if x.mode == invalid {
+ return
+ }
+
+ var y operand
+ arg(&y, 1)
+ if !check.isValidIndex(&y, "length", false) {
+ return
+ }
+
+ x.mode = value
+ x.typ = Typ[String]
+ if check.Types != nil {
+ check.recordBuiltinType(call.Fun, makeSig(x.typ, NewPointer(universeByte), y.typ))
+ }
+
+ case _StringData:
+ // unsafe.StringData(str string) *byte
+ if !check.allowVersion(check.pkg, 1, 20) {
+ check.versionErrorf(call.Fun, "go1.20", "unsafe.StringData")
+ return
+ }
+
+ str, _ := x.typ.(*Basic)
+ if str == nil || str.Kind() != String {
+ check.errorf(x, invalidArg+"%s is not a string", x)
+ return
+ }
+
+ x.mode = value
+ x.typ = NewPointer(universeByte)
+ if check.Types != nil {
+ check.recordBuiltinType(call.Fun, makeSig(x.typ, str))
}
case _Assert:
{"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`},
+ {"SliceData", "var a []int; _ = unsafe.SliceData(a)", `func([]int) *int`},
+ {"SliceData", "type sliceType []int; var a sliceType; _ = unsafe.SliceData(a)", `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`},
+
+ {"StringData", `var s string; _ = unsafe.StringData(s)`, `func(string) *byte`},
+ {"StringData", `var s = "abc"; _ = unsafe.StringData(s)`, `func(string) *byte`},
+
{"assert", `assert(true)`, `invalid type`}, // constant
{"assert", `type B bool; const pred B = 1 < 2; assert(pred)`, `invalid type`}, // constant
_Offsetof
_Sizeof
_Slice
+ _SliceData
+ _String
+ _StringData
// testing support
_Assert
_Real: {"real", 1, false, expression},
_Recover: {"recover", 0, false, statement},
- _Add: {"Add", 2, false, expression},
- _Alignof: {"Alignof", 1, false, expression},
- _Offsetof: {"Offsetof", 1, false, expression},
- _Sizeof: {"Sizeof", 1, false, expression},
- _Slice: {"Slice", 2, false, expression},
+ _Add: {"Add", 2, false, expression},
+ _Alignof: {"Alignof", 1, false, expression},
+ _Offsetof: {"Offsetof", 1, false, expression},
+ _Sizeof: {"Sizeof", 1, false, expression},
+ _Slice: {"Slice", 2, false, expression},
+ _SliceData: {"SliceData", 1, false, expression},
+ _String: {"String", 2, false, expression},
+ _StringData: {"StringData", 1, false, expression},
_Assert: {"assert", 1, false, statement},
_Trace: {"trace", 0, true, statement},
return
}
- typ, _ := under(x.typ).(*Pointer)
- if typ == nil {
+ ptr, _ := under(x.typ).(*Pointer) // TODO(gri) should this be coreType rather than under?
+ if ptr == nil {
check.invalidArg(x, _InvalidUnsafeSlice, "%s is not a pointer", x)
return
}
}
x.mode = value
- x.typ = NewSlice(typ.base)
+ x.typ = NewSlice(ptr.base)
if check.Types != nil {
- check.recordBuiltinType(call.Fun, makeSig(x.typ, typ, y.typ))
+ check.recordBuiltinType(call.Fun, makeSig(x.typ, ptr, y.typ))
+ }
+
+ case _SliceData:
+ // unsafe.SliceData(str string) *byte
+ 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 {
+ check.invalidArg(x, _InvalidUnsafeSliceData, "%s is not a slice", x)
+ return
+ }
+ x.mode = value
+ x.typ = NewPointer(slice.Elem())
+ if check.Types != nil {
+ check.recordBuiltinType(call.Fun, makeSig(x.typ, slice))
+ }
+
+ case _String:
+ // unsafe.String(ptr *byte, len IntegerType) string
+ if !check.allowVersion(check.pkg, 1, 20) {
+ check.errorf(call.Fun, _InvalidUnsafeString, "unsafe.String requires go1.20 or later")
+ return
+ }
+
+ check.assignment(x, NewPointer(universeByte), "argument to unsafe.String")
+ if x.mode == invalid {
+ check.invalidArg(x, _InvalidUnsafeString, "%s is not a *byte", x)
+ return
+ }
+
+ var y operand
+ arg(&y, 1)
+ if !check.isValidIndex(&y, _InvalidUnsafeString, "length", false) {
+ return
+ }
+
+ x.mode = value
+ x.typ = Typ[String]
+ if check.Types != nil {
+ check.recordBuiltinType(call.Fun, makeSig(x.typ, NewPointer(universeByte), y.typ))
+ }
+
+ case _StringData:
+ // unsafe.StringData(str string) *byte
+ if !check.allowVersion(check.pkg, 1, 20) {
+ check.errorf(call.Fun, _InvalidUnsafeStringData, "unsafe.StringData requires go1.20 or later")
+ return
+ }
+
+ str, _ := x.typ.(*Basic)
+ if str == nil || str.kind != String {
+ check.invalidArg(x, _InvalidUnsafeStringData, "%s is not a string", x)
+ return
+ }
+
+ x.mode = value
+ x.typ = NewPointer(universeByte)
+ if check.Types != nil {
+ check.recordBuiltinType(call.Fun, makeSig(x.typ, str))
}
case _Assert:
{"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`},
+ {"SliceData", "var a []int; _ = unsafe.SliceData(a)", `func([]int) *int`},
+ {"SliceData", "type sliceType []int; var a sliceType; _ = unsafe.SliceData(a)", `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`},
+
+ {"StringData", `var s string; _ = unsafe.StringData(s)`, `func(string) *byte`},
+ {"StringData", `var s = "abc"; _ = unsafe.StringData(s)`, `func(string) *byte`},
+
{"assert", `assert(true)`, `invalid type`}, // constant
{"assert", `type B bool; const pred B = 1 < 2; assert(pred)`, `invalid type`}, // constant
// Example:
// type T[P any] struct{ *P }
_MisplacedTypeParam
+
+ // _InvalidUnsafeSliceData occurs when unsafe.SliceData called with type
+ // is not slice
+ //
+ // Example:
+ // import "unsafe"
+ //
+ // var x int
+ // 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.
+ //
+ // Example:
+ // import "unsafe"
+ //
+ // var b [10]byte
+ // 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
)
_Offsetof
_Sizeof
_Slice
+ _SliceData
+ _String
+ _StringData
// testing support
_Assert
_Real: {"real", 1, false, expression},
_Recover: {"recover", 0, false, statement},
- _Add: {"Add", 2, false, expression},
- _Alignof: {"Alignof", 1, false, expression},
- _Offsetof: {"Offsetof", 1, false, expression},
- _Sizeof: {"Sizeof", 1, false, expression},
- _Slice: {"Slice", 2, false, expression},
+ _Add: {"Add", 2, false, expression},
+ _Alignof: {"Alignof", 1, false, expression},
+ _Offsetof: {"Offsetof", 1, false, expression},
+ _Sizeof: {"Sizeof", 1, false, expression},
+ _Slice: {"Slice", 2, false, expression},
+ _SliceData: {"SliceData", 1, false, expression},
+ _String: {"String", 2, false, expression},
+ _StringData: {"StringData", 1, false, expression},
_Assert: {"assert", 1, false, statement},
_Trace: {"trace", 0, true, statement},