go/src/cmd/compile/internal/gc/unsafe.go

91 lines
2.1 KiB
Go

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gc
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types"
)
// evalunsafe evaluates a package unsafe operation and returns the result.
func evalunsafe(n ir.Node) int64 {
switch n.Op() {
case ir.OALIGNOF, ir.OSIZEOF:
n := n.(*ir.UnaryExpr)
n.X = typecheck(n.X, ctxExpr)
n.X = defaultlit(n.X, nil)
tr := n.X.Type()
if tr == nil {
return 0
}
types.CalcSize(tr)
if n.Op() == ir.OALIGNOF {
return int64(tr.Align)
}
return tr.Width
case ir.OOFFSETOF:
// must be a selector.
n := n.(*ir.UnaryExpr)
if n.X.Op() != ir.OXDOT {
base.Errorf("invalid expression %v", n)
return 0
}
sel := n.X.(*ir.SelectorExpr)
// Remember base of selector to find it back after dot insertion.
// Since r->left may be mutated by typechecking, check it explicitly
// first to track it correctly.
sel.X = typecheck(sel.X, ctxExpr)
sbase := sel.X
tsel := typecheck(sel, ctxExpr)
n.X = tsel
if tsel.Type() == nil {
return 0
}
switch tsel.Op() {
case ir.ODOT, ir.ODOTPTR:
break
case ir.OCALLPART:
base.Errorf("invalid expression %v: argument is a method value", n)
return 0
default:
base.Errorf("invalid expression %v", n)
return 0
}
// Sum offsets for dots until we reach sbase.
var v int64
var next ir.Node
for r := tsel; r != sbase; r = next {
switch r.Op() {
case ir.ODOTPTR:
// For Offsetof(s.f), s may itself be a pointer,
// but accessing f must not otherwise involve
// indirection via embedded pointer types.
r := r.(*ir.SelectorExpr)
if r.X != sbase {
base.Errorf("invalid expression %v: selector implies indirection of embedded %v", n, r.X)
return 0
}
fallthrough
case ir.ODOT:
r := r.(*ir.SelectorExpr)
v += r.Offset
next = r.X
default:
ir.Dump("unsafenmagic", tsel)
base.Fatalf("impossible %v node after dot insertion", r.Op())
}
}
return v
}
base.Fatalf("unexpected op %v", n.Op())
return 0
}