Skip to content

Commit

Permalink
[dev.unified] cmd/compile/internal/noder: preserve RTTI for select st…
Browse files Browse the repository at this point in the history
…atements

In a select statement, `case i = <-c: ...` may require an implicit
conversion of the received value to i's type, but walk does not expect
a conversion here. Instead, typecheck actually discards the
conversion (resulting in ill-typed IR), and then relies on it being
reinserted later when walk desugars the assignment.

However, that might lose the explicit RTTI operands we've set for
conversions to interface type, so explicitly introduce a temporary
variable and rewrite as `case tmp := <-c: i = tmp; ...`, which is
semantically equivalent and allows the `i = tmp` assignment to
maintain the explicit RTTI without confusing the rest of the compiler
frontend.

Change-Id: Ie6c4dc9b19437e83970cd3ce83420813b8a47dc4
Reviewed-on: https://go-review.googlesource.com/c/go/+/418098
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Keith Randall <khr@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
  • Loading branch information
mdempsky committed Jul 19, 2022
1 parent e376746 commit 878439c
Showing 1 changed file with 38 additions and 7 deletions.
45 changes: 38 additions & 7 deletions src/cmd/compile/internal/noder/reader.go
Expand Up @@ -1477,6 +1477,32 @@ func (r *reader) selectStmt(label *types.Sym) ir.Node {
comm := r.stmt()
body := r.stmts()

// "case i = <-c: ..." may require an implicit conversion (e.g.,
// see fixedbugs/bug312.go). Currently, typecheck throws away the
// implicit conversion and relies on it being reinserted later,
// but that would lose any explicit RTTI operands too. To preserve
// RTTI, we rewrite this as "case tmp := <-c: i = tmp; ...".
if as, ok := comm.(*ir.AssignStmt); ok && as.Op() == ir.OAS && !as.Def {
if conv, ok := as.Y.(*ir.ConvExpr); ok && conv.Op() == ir.OCONVIFACE {
base.AssertfAt(conv.Implicit(), conv.Pos(), "expected implicit conversion: %v", conv)

recv := conv.X
base.AssertfAt(recv.Op() == ir.ORECV, recv.Pos(), "expected receive expression: %v", recv)

tmp := r.temp(pos, recv.Type())

// Replace comm with `tmp := <-c`.
tmpAs := ir.NewAssignStmt(pos, tmp, recv)
tmpAs.Def = true
tmpAs.PtrInit().Append(ir.NewDecl(pos, ir.ODCL, tmp))
comm = tmpAs

// Change original assignment to `i = tmp`, and prepend to body.
conv.X = tmp
body = append([]ir.Node{as}, body...)
}
}

// multiExpr will have desugared a comma-ok receive expression
// into a separate statement. However, the rest of the compiler
// expects comm to be the OAS2RECV statement itself, so we need to
Expand Down Expand Up @@ -1887,17 +1913,11 @@ func (r *reader) multiExpr() []ir.Node {
pos := r.pos()
expr := r.expr()

// See typecheck.typecheckargs.
curfn := r.curfn
if curfn == nil {
curfn = typecheck.InitTodoFunc
}

results := make([]ir.Node, r.Len())
as := ir.NewAssignListStmt(pos, ir.OAS2, nil, []ir.Node{expr})
as.Def = true
for i := range results {
tmp := typecheck.TempAt(pos, curfn, r.typ())
tmp := r.temp(pos, r.typ())
as.PtrInit().Append(ir.NewDecl(pos, ir.ODCL, tmp))
as.Lhs.Append(tmp)

Expand Down Expand Up @@ -1927,6 +1947,17 @@ func (r *reader) multiExpr() []ir.Node {
return exprs
}

// temp returns a new autotemp of the specified type.
func (r *reader) temp(pos src.XPos, typ *types.Type) *ir.Name {
// See typecheck.typecheckargs.
curfn := r.curfn
if curfn == nil {
curfn = typecheck.InitTodoFunc
}

return typecheck.TempAt(pos, curfn, typ)
}

func (r *reader) compLit() ir.Node {
r.Sync(pkgbits.SyncCompLit)
pos := r.pos()
Expand Down

0 comments on commit 878439c

Please sign in to comment.