Skip to content

Commit 050b408

Browse files
committed
go/types: implement unsafe.Add and unsafe.Slice
Updates #19367. Updates #40481. Change-Id: Id2b2d2e3e716f91f0dd9e5102689a1ba90a819e4 Reviewed-on: https://go-review.googlesource.com/c/go/+/312213 Run-TryBot: Matthew Dempsky <[email protected]> TryBot-Result: Go Bot <[email protected]> Trust: Matthew Dempsky <[email protected]> Trust: Robert Griesemer <[email protected]> Reviewed-by: Robert Griesemer <[email protected]> Reviewed-by: Robert Findley <[email protected]>
1 parent 1da05eb commit 050b408

File tree

5 files changed

+94
-5
lines changed

5 files changed

+94
-5
lines changed

src/go/types/builtins.go

+39
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,25 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
586586
check.recordBuiltinType(call.Fun, makeSig(x.typ))
587587
}
588588

589+
case _Add:
590+
// unsafe.Add(ptr unsafe.Pointer, len IntegerType) unsafe.Pointer
591+
check.assignment(x, Typ[UnsafePointer], "argument to unsafe.Add")
592+
if x.mode == invalid {
593+
return
594+
}
595+
596+
var y operand
597+
arg(&y, 1)
598+
if !check.isValidIndex(&y, _InvalidUnsafeAdd, "length", true) {
599+
return
600+
}
601+
602+
x.mode = value
603+
x.typ = Typ[UnsafePointer]
604+
if check.Types != nil {
605+
check.recordBuiltinType(call.Fun, makeSig(x.typ, x.typ, y.typ))
606+
}
607+
589608
case _Alignof:
590609
// unsafe.Alignof(x T) uintptr
591610
if asTypeParam(x.typ) != nil {
@@ -663,6 +682,26 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
663682
x.typ = Typ[Uintptr]
664683
// result is constant - no need to record signature
665684

685+
case _Slice:
686+
// unsafe.Slice(ptr *T, len IntegerType) []T
687+
typ := asPointer(x.typ)
688+
if typ == nil {
689+
check.invalidArg(x, _InvalidUnsafeSlice, "%s is not a pointer", x)
690+
return
691+
}
692+
693+
var y operand
694+
arg(&y, 1)
695+
if !check.isValidIndex(&y, _InvalidUnsafeSlice, "length", false) {
696+
return
697+
}
698+
699+
x.mode = value
700+
x.typ = NewSlice(typ.base)
701+
if check.Types != nil {
702+
check.recordBuiltinType(call.Fun, makeSig(x.typ, typ, y.typ))
703+
}
704+
666705
case _Assert:
667706
// assert(pred) causes a typechecker error if pred is false.
668707
// The result of assert is the value of pred if there is no error.

src/go/types/builtins_test.go

+7
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ var builtinCalls = []struct {
107107
{"recover", `recover()`, `func() interface{}`},
108108
{"recover", `_ = recover()`, `func() interface{}`},
109109

110+
{"Add", `var p unsafe.Pointer; _ = unsafe.Add(p, -1.0)`, `func(unsafe.Pointer, int) unsafe.Pointer`},
111+
{"Add", `var p unsafe.Pointer; var n uintptr; _ = unsafe.Add(p, n)`, `func(unsafe.Pointer, uintptr) unsafe.Pointer`},
112+
{"Add", `_ = unsafe.Add(nil, 0)`, `func(unsafe.Pointer, int) unsafe.Pointer`},
113+
110114
{"Alignof", `_ = unsafe.Alignof(0)`, `invalid type`}, // constant
111115
{"Alignof", `var x struct{}; _ = unsafe.Alignof(x)`, `invalid type`}, // constant
112116

@@ -116,6 +120,9 @@ var builtinCalls = []struct {
116120
{"Sizeof", `_ = unsafe.Sizeof(0)`, `invalid type`}, // constant
117121
{"Sizeof", `var x struct{}; _ = unsafe.Sizeof(x)`, `invalid type`}, // constant
118122

123+
{"Slice", `var p *int; _ = unsafe.Slice(p, 1)`, `func(*int, int) []int`},
124+
{"Slice", `var p *byte; var n uintptr; _ = unsafe.Slice(p, n)`, `func(*byte, uintptr) []byte`},
125+
119126
{"assert", `assert(true)`, `invalid type`}, // constant
120127
{"assert", `type B bool; const pred B = 1 < 2; assert(pred)`, `invalid type`}, // constant
121128

src/go/types/check.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -329,14 +329,14 @@ func (check *Checker) recordTypeAndValue(x ast.Expr, mode operandMode, typ Type,
329329
}
330330

331331
func (check *Checker) recordBuiltinType(f ast.Expr, sig *Signature) {
332-
// f must be a (possibly parenthesized) identifier denoting a built-in
333-
// (built-ins in package unsafe always produce a constant result and
334-
// we don't record their signatures, so we don't see qualified idents
335-
// here): record the signature for f and possible children.
332+
// f must be a (possibly parenthesized, possibly qualified)
333+
// identifier denoting a built-in (including unsafe's non-constant
334+
// functions Add and Slice): record the signature for f and possible
335+
// children.
336336
for {
337337
check.recordTypeAndValue(f, builtin, sig, nil)
338338
switch p := f.(type) {
339-
case *ast.Ident:
339+
case *ast.Ident, *ast.SelectorExpr:
340340
return // we're done
341341
case *ast.ParenExpr:
342342
f = p.X

src/go/types/errorcodes.go

+39
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,45 @@ const (
883883
// var _ = real(int(1))
884884
_InvalidReal
885885

886+
// _InvalidUnsafeAdd occurs when unsafe.Add is called with a
887+
// length argument that is not of integer type.
888+
//
889+
// Example:
890+
// import "unsafe"
891+
//
892+
// var p unsafe.Pointer
893+
// var _ = unsafe.Add(p, float64(1))
894+
_InvalidUnsafeAdd
895+
896+
// _InvalidUnsafeSlice occurs when unsafe.Slice is called with a
897+
// pointer argument that is not of pointer type or a length argument
898+
// that is not of integer type, negative, or out of bounds.
899+
//
900+
// Example:
901+
// import "unsafe"
902+
//
903+
// var x int
904+
// var _ = unsafe.Slice(x, 1)
905+
//
906+
// Example:
907+
// import "unsafe"
908+
//
909+
// var x int
910+
// var _ = unsafe.Slice(&x, float64(1))
911+
//
912+
// Example:
913+
// import "unsafe"
914+
//
915+
// var x int
916+
// var _ = unsafe.Slice(&x, -1)
917+
//
918+
// Example:
919+
// import "unsafe"
920+
//
921+
// var x int
922+
// var _ = unsafe.Slice(&x, uint64(1) << 63)
923+
_InvalidUnsafeSlice
924+
886925
/* exprs > assertion */
887926

888927
// _InvalidAssert occurs when a type assertion is applied to a

src/go/types/universe.go

+4
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,11 @@ const (
137137
_Recover
138138

139139
// package unsafe
140+
_Add
140141
_Alignof
141142
_Offsetof
142143
_Sizeof
144+
_Slice
143145

144146
// testing support
145147
_Assert
@@ -168,9 +170,11 @@ var predeclaredFuncs = [...]struct {
168170
_Real: {"real", 1, false, expression},
169171
_Recover: {"recover", 0, false, statement},
170172

173+
_Add: {"Add", 2, false, expression},
171174
_Alignof: {"Alignof", 1, false, expression},
172175
_Offsetof: {"Offsetof", 1, false, expression},
173176
_Sizeof: {"Sizeof", 1, false, expression},
177+
_Slice: {"Slice", 2, false, expression},
174178

175179
_Assert: {"assert", 1, false, statement},
176180
_Trace: {"trace", 0, true, statement},

0 commit comments

Comments
 (0)