Skip to content

Commit 2e457b3

Browse files
mdempskygopherbot
authored andcommitted
cmd/compile/internal/noder: handle unsafe.Sizeof, etc in unified IR
Previously, the unified frontend implemented unsafe.Sizeof, etc that involved derived types by constructing a normal OSIZEOF, etc expression, including fully instantiating their argument. (When unsafe.Sizeof is applied to a non-generic type, types2 handles constant folding it.) This worked, but involves unnecessary work, since all we really need to track is the argument type (and the field selections, for unsafe.Offsetof). Further, the argument expression could generate temporary variables, which would then go unused after typecheck replaced the OSIZEOF expression with an OLITERAL. This results in compiler failures after CL 523315, which made later passes stricter about expecting the frontend to not construct unused temporaries. Fixes #62515. Change-Id: I37baed048fd2e35648c59243f66c97c24413aa94 Reviewed-on: https://go-review.googlesource.com/c/go/+/527097 Reviewed-by: Keith Randall <khr@golang.org> Reviewed-by: Keith Randall <khr@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Auto-Submit: Matthew Dempsky <mdempsky@google.com>
1 parent f72693d commit 2e457b3

File tree

5 files changed

+88
-0
lines changed

5 files changed

+88
-0
lines changed

src/cmd/compile/internal/ir/const.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ func NewString(pos src.XPos, s string) Node {
2929
return NewBasicLit(pos, types.UntypedString, constant.MakeString(s))
3030
}
3131

32+
// NewUintptr returns an OLITERAL representing v as a uintptr.
33+
func NewUintptr(pos src.XPos, v int64) Node {
34+
return NewBasicLit(pos, types.Types[types.TUINTPTR], constant.MakeInt64(v))
35+
}
36+
3237
// NewOne returns an OLITERAL representing 1 with the given type.
3338
func NewOne(pos src.XPos, typ *types.Type) Node {
3439
var val constant.Value

src/cmd/compile/internal/noder/codes.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ const (
5555
exprConvert
5656
exprNew
5757
exprMake
58+
exprSizeof
59+
exprAlignof
60+
exprOffsetof
5861
exprNil
5962
exprFuncInst
6063
exprRecv

src/cmd/compile/internal/noder/reader.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2459,6 +2459,26 @@ func (r *reader) expr() (res ir.Node) {
24592459
typ := r.exprType()
24602460
return typecheck.Expr(ir.NewUnaryExpr(pos, ir.ONEW, typ))
24612461

2462+
case exprSizeof:
2463+
return ir.NewUintptr(r.pos(), r.typ().Size())
2464+
2465+
case exprAlignof:
2466+
return ir.NewUintptr(r.pos(), r.typ().Alignment())
2467+
2468+
case exprOffsetof:
2469+
pos := r.pos()
2470+
typ := r.typ()
2471+
types.CalcSize(typ)
2472+
2473+
var offset int64
2474+
for i := r.Len(); i >= 0; i-- {
2475+
field := typ.Field(r.Len())
2476+
offset += field.Offset
2477+
typ = field.Type
2478+
}
2479+
2480+
return ir.NewUintptr(pos, offset)
2481+
24622482
case exprReshape:
24632483
typ := r.typ()
24642484
x := r.expr()

src/cmd/compile/internal/noder/writer.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1965,6 +1965,39 @@ func (w *writer) expr(expr syntax.Expr) {
19651965
w.exprType(nil, expr.ArgList[0])
19661966
return
19671967

1968+
case "Sizeof":
1969+
assert(len(expr.ArgList) == 1)
1970+
assert(!expr.HasDots)
1971+
1972+
w.Code(exprSizeof)
1973+
w.pos(expr)
1974+
w.typ(w.p.typeOf(expr.ArgList[0]))
1975+
return
1976+
1977+
case "Alignof":
1978+
assert(len(expr.ArgList) == 1)
1979+
assert(!expr.HasDots)
1980+
1981+
w.Code(exprAlignof)
1982+
w.pos(expr)
1983+
w.typ(w.p.typeOf(expr.ArgList[0]))
1984+
return
1985+
1986+
case "Offsetof":
1987+
assert(len(expr.ArgList) == 1)
1988+
assert(!expr.HasDots)
1989+
selector := syntax.Unparen(expr.ArgList[0]).(*syntax.SelectorExpr)
1990+
index := w.p.info.Selections[selector].Index()
1991+
1992+
w.Code(exprOffsetof)
1993+
w.pos(expr)
1994+
w.typ(deref2(w.p.typeOf(selector.X)))
1995+
w.Len(len(index) - 1)
1996+
for _, idx := range index {
1997+
w.Len(idx)
1998+
}
1999+
return
2000+
19682001
case "append":
19692002
rtype = sliceElem(w.p.typeOf(expr))
19702003
case "copy":

test/fixedbugs/issue62515.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// compile
2+
3+
// Copyright 2023 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
// Unified frontend generated unnecessary temporaries for expressions
8+
// within unsafe.Sizeof, etc functions.
9+
10+
package main
11+
12+
import "unsafe"
13+
14+
func F[G int](g G) (uintptr, uintptr, uintptr) {
15+
var c chan func() int
16+
type s struct {
17+
g G
18+
x []int
19+
}
20+
return unsafe.Sizeof(s{g, make([]int, (<-c)())}),
21+
unsafe.Alignof(s{g, make([]int, (<-c)())}),
22+
unsafe.Offsetof(s{g, make([]int, (<-c)())}.x)
23+
}
24+
25+
func main() {
26+
F(0)
27+
}

0 commit comments

Comments
 (0)