]> Cypherpunks repositories - gostls13.git/commitdiff
go/types,types2: add support for unsafe.{String,StringData,SliceData}
authorcuiweixie <cuiweixie@gmail.com>
Sun, 14 Aug 2022 06:41:19 +0000 (14:41 +0800)
committerRobert Griesemer <gri@google.com>
Wed, 24 Aug 2022 22:39:01 +0000 (22:39 +0000)
For #53003
Change-Id: Id3125268523fed855ffac20cde6128010e3513f0
Reviewed-on: https://go-review.googlesource.com/c/go/+/423754
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/cmd/compile/internal/types2/builtins.go
src/cmd/compile/internal/types2/builtins_test.go
src/cmd/compile/internal/types2/universe.go
src/go/types/builtins.go
src/go/types/builtins_test.go
src/go/types/errorcodes.go
src/go/types/universe.go

index b504c2bd5d58518bdabe87fe094fce62d26ffd26..c67e064257c5acb06d837707ef0fd3d2a1dd37da 100644 (file)
@@ -725,8 +725,8 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
                        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
                }
@@ -738,9 +738,71 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
                }
 
                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:
index ad8873a7d4141865f512779f3b8f72c4ddc6f435..fb9db73d704fb8b29eb069b8e374173014bf30e1 100644 (file)
@@ -129,6 +129,15 @@ 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`},
 
+       {"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
 
index 9292924f234b8d2b150a5155a0e5a6f697d21842..301526c8d6095122dded7753b2644a6461f080fb 100644 (file)
@@ -165,6 +165,9 @@ const (
        _Offsetof
        _Sizeof
        _Slice
+       _SliceData
+       _String
+       _StringData
 
        // testing support
        _Assert
@@ -193,11 +196,14 @@ var predeclaredFuncs = [...]struct {
        _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},
index 463d814a2f32f877cffe59cf403238cc544ea526..4f9b791ce7c7da5d02a9ca2590edd93cd1815164 100644 (file)
@@ -734,8 +734,8 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                        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
                }
@@ -747,9 +747,71 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                }
 
                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:
index 7e967a36e10e0d0fdd264032e8842bef1aacff1f..deabe21272fe8f7f70620b0700ce25e6f71f1de9 100644 (file)
@@ -130,6 +130,15 @@ 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`},
 
+       {"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
 
index 64cf24c96a1545604a379819f10dc3422b46883f..6448eda15558bffaf8058caacd5a3b6b19c10813 100644 (file)
@@ -1389,4 +1389,39 @@ const (
        // 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
 )
index 8ac48e506ef2105a4e6045622da1bfb0099f790e..8551ee00ff1b393b7803e1ba4cb6f5ce1a4968ab 100644 (file)
@@ -166,6 +166,9 @@ const (
        _Offsetof
        _Sizeof
        _Slice
+       _SliceData
+       _String
+       _StringData
 
        // testing support
        _Assert
@@ -194,11 +197,14 @@ var predeclaredFuncs = [...]struct {
        _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},