| // 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 |
| |
| // evalunsafe evaluates a package unsafe operation and returns the result. |
| func evalunsafe(n *Node) int64 { |
| switch n.Op { |
| case OALIGNOF, OSIZEOF: |
| n.Left = typecheck(n.Left, Erv) |
| n.Left = defaultlit(n.Left, nil) |
| tr := n.Left.Type |
| if tr == nil { |
| yyerror("invalid expression %v", n) |
| return 0 |
| } |
| dowidth(tr) |
| if n.Op == OALIGNOF { |
| return int64(tr.Align) |
| } |
| return tr.Width |
| |
| case OOFFSETOF: |
| // must be a selector. |
| if n.Left.Op != OXDOT { |
| yyerror("invalid expression %v", n) |
| return 0 |
| } |
| |
| // 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. |
| n.Left.Left = typecheck(n.Left.Left, Erv) |
| base := n.Left.Left |
| |
| n.Left = typecheck(n.Left, Erv) |
| switch n.Left.Op { |
| case ODOT, ODOTPTR: |
| break |
| case OCALLPART: |
| yyerror("invalid expression %v: argument is a method value", n) |
| return 0 |
| default: |
| yyerror("invalid expression %v", n) |
| return 0 |
| } |
| |
| // Sum offsets for dots until we reach base. |
| var v int64 |
| for r := n.Left; r != base; r = r.Left { |
| switch r.Op { |
| case ODOTPTR: |
| // For Offsetof(s.f), s may itself be a pointer, |
| // but accessing f must not otherwise involve |
| // indirection via embedded pointer types. |
| if r.Left != base { |
| yyerror("invalid expression %v: selector implies indirection of embedded %v", n, r.Left) |
| return 0 |
| } |
| fallthrough |
| case ODOT: |
| v += r.Xoffset |
| default: |
| Dump("unsafenmagic", n.Left) |
| Fatalf("impossible %#v node after dot insertion", r.Op) |
| } |
| } |
| return v |
| } |
| |
| Fatalf("unexpected op %v", n.Op) |
| return 0 |
| } |