aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Dempsky <mdempsky@google.com>2022-07-18 12:41:56 -0700
committerMatthew Dempsky <mdempsky@google.com>2022-07-19 23:30:39 +0000
commit878439cfe592165bdeaeed037bf1d3351e638853 (patch)
treed33491449b8207a4fddd8d7371b4599dedc3e6d4
parente376746e54aae4fb519f50bbe42656a2d34df285 (diff)
downloadgo-878439cfe592165bdeaeed037bf1d3351e638853.tar.gz
go-878439cfe592165bdeaeed037bf1d3351e638853.zip
[dev.unified] cmd/compile/internal/noder: preserve RTTI for select statements
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>
-rw-r--r--src/cmd/compile/internal/noder/reader.go45
1 files changed, 38 insertions, 7 deletions
diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go
index 6b47c11749..8cb0df182c 100644
--- a/src/cmd/compile/internal/noder/reader.go
+++ b/src/cmd/compile/internal/noder/reader.go
@@ -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
@@ -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)
@@ -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()