diff --git a/src/cmd/compile/internal/gc/unsafe.go b/src/cmd/compile/internal/gc/unsafe.go index 7cac8516c3..f69f6f35f0 100644 --- a/src/cmd/compile/internal/gc/unsafe.go +++ b/src/cmd/compile/internal/gc/unsafe.go @@ -6,11 +6,7 @@ package gc import "cmd/internal/obj" -// look for -// unsafe.Sizeof -// unsafe.Offsetof -// unsafe.Alignof -// rewrite with a constant +// unsafenmagic rewrites calls to package unsafe's functions into constants. func unsafenmagic(nn *Node) *Node { fn := nn.Left args := nn.List @@ -34,7 +30,8 @@ func unsafenmagic(nn *Node) *Node { r := args.First() var v int64 - if s.Name == "Sizeof" { + switch s.Name { + case "Alignof", "Sizeof": typecheck(&r, Erv) defaultlit(&r, nil) tr := r.Type @@ -42,11 +39,13 @@ func unsafenmagic(nn *Node) *Node { goto bad } dowidth(tr) - v = tr.Width - goto yes - } + if s.Name == "Alignof" { + v = int64(tr.Align) + } else { + v = tr.Width + } - if s.Name == "Offsetof" { + case "Offsetof": // must be a selector. if r.Op != OXDOT { goto bad @@ -56,35 +55,33 @@ func unsafenmagic(nn *Node) *Node { // 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) switch r.Op { case ODOT, ODOTPTR: break - case OCALLPART: Yyerror("invalid expression %v: argument is a method value", nn) - v = 0 goto ret - default: goto bad } - v = 0 - - // add offsets for inserted dots. - var r1 *Node - for r1 = r; r1.Left != base; r1 = r1.Left { + // Sum offsets for dots until we reach base. + for r1 := r; r1 != base; r1 = r1.Left { switch r1.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 r1.Left != base { + Yyerror("invalid expression %v: selector implies indirection of embedded %v", nn, r1.Left) + goto ret + } + fallthrough case ODOT: v += r1.Xoffset - - case ODOTPTR: - Yyerror("invalid expression %v: selector implies indirection of embedded %v", nn, r1.Left) - goto ret - default: Dump("unsafenmagic", r) Fatalf("impossible %v node after dot insertion", Oconv(r1.Op, obj.FmtSharp)) @@ -92,51 +89,20 @@ func unsafenmagic(nn *Node) *Node { } } - v += r1.Xoffset - goto yes + default: + return nil } - if s.Name == "Alignof" { - typecheck(&r, Erv) - defaultlit(&r, nil) - tr := r.Type - if tr == nil { - goto bad - } - - var f [2]*Type - f[0] = typ(TFIELD) - f[0].Type = Types[TUINT8] - f[1] = typ(TFIELD) - f[1].Type = tr - - // make struct { byte; T; } - t := typ(TSTRUCT) - t.SetFields(f[:]) - - // compute struct widths - dowidth(t) - - // the offset of T is its required alignment - v = t.Field(1).Width - - goto yes - } - - return nil - -bad: - Yyerror("invalid expression %v", nn) - v = 0 - goto ret - -yes: if args.Len() > 1 { Yyerror("extra arguments for %v", s) } + goto ret + +bad: + Yyerror("invalid expression %v", nn) - // any side effects disappear; ignore init ret: + // any side effects disappear; ignore init var val Val val.U = new(Mpint) Mpmovecfix(val.U.(*Mpint), v)