summaryrefslogtreecommitdiff
path: root/src/cmd/gc/unsafe.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/unsafe.c')
-rw-r--r--src/cmd/gc/unsafe.c42
1 files changed, 37 insertions, 5 deletions
diff --git a/src/cmd/gc/unsafe.c b/src/cmd/gc/unsafe.c
index 95200ad41..ff08c0eef 100644
--- a/src/cmd/gc/unsafe.c
+++ b/src/cmd/gc/unsafe.c
@@ -16,10 +16,10 @@
Node*
unsafenmagic(Node *nn)
{
- Node *r, *n;
+ Node *r, *n, *base, *r1;
Sym *s;
Type *t, *tr;
- long v;
+ vlong v;
Val val;
Node *fn;
NodeList *args;
@@ -49,11 +49,43 @@ unsafenmagic(Node *nn)
goto yes;
}
if(strcmp(s->name, "Offsetof") == 0) {
- typecheck(&r, Erv);
- if(r->op != ODOT && r->op != ODOTPTR)
+ // must be a selector.
+ if(r->op != OXDOT)
goto bad;
+ // 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.
+ typecheck(&r->left, Erv);
+ base = r->left;
typecheck(&r, Erv);
- v = r->xoffset;
+ switch(r->op) {
+ case ODOT:
+ case ODOTPTR:
+ break;
+ case OCALLPART:
+ yyerror("invalid expression %N: argument is a method value", nn);
+ v = 0;
+ goto ret;
+ default:
+ goto bad;
+ }
+ v = 0;
+ // add offsets for inserted dots.
+ for(r1=r; r1->left!=base; r1=r1->left) {
+ switch(r1->op) {
+ case ODOT:
+ v += r1->xoffset;
+ break;
+ case ODOTPTR:
+ yyerror("invalid expression %N: selector implies indirection of embedded %N", nn, r1->left);
+ goto ret;
+ default:
+ dump("unsafenmagic", r);
+ fatal("impossible %#O node after dot insertion", r1->op);
+ goto bad;
+ }
+ }
+ v += r1->xoffset;
goto yes;
}
if(strcmp(s->name, "Alignof") == 0) {