Skip to content

Commit

Permalink
interp: implement unsafe.Offsetof
Browse files Browse the repository at this point in the history
Offsetof returns the offset of a field in a struct. It is computed
during parsing at CFG, due to the constraint of operating on a
struct selector expression.

With this function, the support of 'unsafe' package is now
complete in yaegi.

Fixes #1062.
  • Loading branch information
mvertes authored Apr 14, 2021
1 parent 9aeb78f commit 3e3f8d5
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 4 deletions.
10 changes: 6 additions & 4 deletions _test/unsafe5.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ type S struct {
}

func main() {
size := unsafe.Sizeof(S{})
align := unsafe.Alignof(S{})
x := S{}
size := unsafe.Sizeof(x)
align := unsafe.Alignof(x.Y)
offset := unsafe.Offsetof(x.Z)

fmt.Println(size, align)
fmt.Println(size, align, offset)
}

// Output:
// 24 8
// 24 8 16
18 changes: 18 additions & 0 deletions interp/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,20 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
}
}
}
case isOffsetof(n):
if len(n.child) != 2 || n.child[1].kind != selectorExpr || !isStruct(n.child[1].child[0].typ) {
err = n.cfgErrorf("Offsetof argument: invalid expression")
break
}
c1 := n.child[1]
field, ok := c1.child[0].typ.rtype.FieldByName(c1.child[1].ident)
if !ok {
err = n.cfgErrorf("struct does not contain field: %s", c1.child[1].ident)
break
}
n.typ = &itype{cat: valueT, rtype: reflect.TypeOf(field.Offset)}
n.rval = reflect.ValueOf(field.Offset)
n.gen = nop
default:
err = check.arguments(n, n.child[1:], n.child[0], n.action == aCallSlice)
if err != nil {
Expand Down Expand Up @@ -2411,6 +2425,10 @@ func isBinCall(n *node) bool {
return isCall(n) && n.child[0].typ.cat == valueT && n.child[0].typ.rtype.Kind() == reflect.Func
}

func isOffsetof(n *node) bool {
return isCall(n) && n.child[0].typ.cat == valueT && n.child[0].rval.String() == "Offsetof"
}

func mustReturnValue(n *node) bool {
if len(n.child) < 2 {
return false
Expand Down
1 change: 1 addition & 0 deletions stdlib/unsafe/unsafe.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func init() {
// Add builtin functions to unsafe.
Symbols["unsafe"]["Sizeof"] = reflect.ValueOf(sizeof)
Symbols["unsafe"]["Alignof"] = reflect.ValueOf(alignof)
Symbols["unsafe"]["Offsetof"] = reflect.ValueOf("Offsetof") // This symbol is handled directly in interpreter.
}

func convert(from, to reflect.Type) func(src, dest reflect.Value) {
Expand Down

0 comments on commit 3e3f8d5

Please sign in to comment.