Skip to content

Commit 6985ab2

Browse files
committed
cmd/compile: fix unified IR's pointer-shaping
In CL 424734, I implemented pointer shaping for unified IR. Evidently though, we didn't have any test cases that check that uses of pointer-shaped expressions were handled correctly. In the reported test case, the struct field "children items[*node[T]]" gets shaped to "children items[go.shape.*uint8]" (underlying type "[]go.shape.*uint8"); and so the expression "n.children[i]" has type "go.shape.*uint8" and the ".items" field selection expression fails. The fix implemented in this CL is that any expression of derived type now gets an explicit "reshape" operation applied to it, to ensure it has the appropriate type for its context. E.g., the "n.children[i]" OINDEX expression above gets "reshaped" from "go.shape.*uint8" to "*node[go.shape.int]", allowing the field selection to succeed. This CL also adds a "-d=reshape" compiler debugging flag, because I anticipate debugging reshaping operations will be something to come up again in the future. Fixes #54535. Change-Id: Id847bd8f51300d2491d679505ee4d2e974ca972a Reviewed-on: https://go-review.googlesource.com/c/go/+/424936 Reviewed-by: David Chase <[email protected]> Reviewed-by: hopehook <[email protected]> Reviewed-by: Cuong Manh Le <[email protected]> Run-TryBot: Matthew Dempsky <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent 0a6e1fa commit 6985ab2

File tree

5 files changed

+90
-1
lines changed

5 files changed

+90
-1
lines changed

src/cmd/compile/internal/base/debug.go

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ type DebugFlags struct {
3434
NoRefName int `help:"do not include referenced symbol names in object file"`
3535
PCTab string `help:"print named pc-value table\nOne of: pctospadj, pctofile, pctoline, pctoinline, pctopcdata"`
3636
Panic int `help:"show all compiler panics"`
37+
Reshape int `help:"print information about expression reshaping"`
3738
Slice int `help:"print information about slice compilation"`
3839
SoftFloat int `help:"force compiler to emit soft-float code"`
3940
SyncFrames int `help:"how many writer stack frames to include at sync points in unified export data"`

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

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ const (
5858
exprNil
5959
exprFuncInst
6060
exprRecv
61+
exprReshape
6162
)
6263

6364
type codeAssign int

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

+36-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ func (pr *pkgReader) newReader(k pkgbits.RelocKind, idx pkgbits.Index, marker pk
8989
}
9090
}
9191

92-
// A writer provides APIs for reading an individual element.
92+
// A reader provides APIs for reading an individual element.
9393
type reader struct {
9494
pkgbits.Decoder
9595

@@ -2367,6 +2367,41 @@ func (r *reader) expr() (res ir.Node) {
23672367
typ := r.exprType()
23682368
return typecheck.Expr(ir.NewUnaryExpr(pos, ir.ONEW, typ))
23692369

2370+
case exprReshape:
2371+
typ := r.typ()
2372+
x := r.expr()
2373+
2374+
if types.IdenticalStrict(x.Type(), typ) {
2375+
return x
2376+
}
2377+
2378+
// Comparison expressions are constructed as "untyped bool" still.
2379+
//
2380+
// TODO(mdempsky): It should be safe to reshape them here too, but
2381+
// maybe it's better to construct them with the proper type
2382+
// instead.
2383+
if x.Type() == types.UntypedBool && typ.IsBoolean() {
2384+
return x
2385+
}
2386+
2387+
base.AssertfAt(x.Type().HasShape() || typ.HasShape(), x.Pos(), "%L and %v are not shape types", x, typ)
2388+
base.AssertfAt(types.Identical(x.Type(), typ), x.Pos(), "%L is not shape-identical to %v", x, typ)
2389+
2390+
// We use ir.HasUniquePos here as a check that x only appears once
2391+
// in the AST, so it's okay for us to call SetType without
2392+
// breaking any other uses of it.
2393+
//
2394+
// Notably, any ONAMEs should already have the exactly right shape
2395+
// type and been caught by types.IdenticalStrict above.
2396+
base.AssertfAt(ir.HasUniquePos(x), x.Pos(), "cannot call SetType(%v) on %L", typ, x)
2397+
2398+
if base.Debug.Reshape != 0 {
2399+
base.WarnfAt(x.Pos(), "reshaping %L to %v", x, typ)
2400+
}
2401+
2402+
x.SetType(typ)
2403+
return x
2404+
23702405
case exprConvert:
23712406
implicit := r.Bool()
23722407
typ := r.typ()

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

+15
Original file line numberDiff line numberDiff line change
@@ -1629,6 +1629,16 @@ func (w *writer) expr(expr syntax.Expr) {
16291629
w.typ(tv.Type)
16301630
return
16311631
}
1632+
1633+
// With shape types (and particular pointer shaping), we may have
1634+
// an expression of type "go.shape.*uint8", but need to reshape it
1635+
// to another shape-identical type to allow use in field
1636+
// selection, indexing, etc.
1637+
if typ := tv.Type; !tv.IsBuiltin() && !isTuple(typ) && !isUntyped(typ) {
1638+
w.Code(exprReshape)
1639+
w.typ(typ)
1640+
// fallthrough
1641+
}
16321642
}
16331643

16341644
if obj != nil {
@@ -2199,6 +2209,11 @@ func isUntyped(typ types2.Type) bool {
21992209
return ok && basic.Info()&types2.IsUntyped != 0
22002210
}
22012211

2212+
func isTuple(typ types2.Type) bool {
2213+
_, ok := typ.(*types2.Tuple)
2214+
return ok
2215+
}
2216+
22022217
func (w *writer) itab(typ, iface types2.Type) {
22032218
typ = types2.Default(typ)
22042219
iface = types2.Default(iface)

test/typeparam/issue54535.go

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// run
2+
3+
// Copyright 2022 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+
package main
8+
9+
type node[T any] struct {
10+
items items[T]
11+
children items[*node[T]]
12+
}
13+
14+
func (n *node[T]) f(i int, j int) bool {
15+
if len(n.children[i].items) < j {
16+
return false
17+
}
18+
return true
19+
}
20+
21+
type items[T any] []T
22+
23+
func main() {
24+
_ = node[int]{}
25+
_ = f[int]
26+
}
27+
28+
type s[T, U any] struct {
29+
a T
30+
c U
31+
}
32+
33+
func f[T any]() {
34+
var x s[*struct{ b T }, *struct{ d int }]
35+
_ = x.a.b
36+
_ = x.c.d
37+
}

0 commit comments

Comments
 (0)