]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: fix mis-compilation when switching over channels
authorCuong Manh Le <cuong.manhle.vn@gmail.com>
Mon, 24 Jun 2024 19:35:19 +0000 (02:35 +0700)
committerGopher Robot <gobot@golang.org>
Wed, 3 Jul 2024 18:07:19 +0000 (18:07 +0000)
CL 418101 changes Unified IR writer to force mixed tag/case to have
common type, emitting the implicit conversion if any of the case values
are not assignable to the tag value's type.

However, the Go spec definition of equality is non-transitive for
channels stored in interfaces, causing incorrect behavior with channel
values comparison.

To fix it, don't emit the implicit conversions if tag type is channel.

Fixes #67190

Change-Id: I9a29d9ce3c7978f0689e9502ba6f15660c763d16
Reviewed-on: https://go-review.googlesource.com/c/go/+/594575
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Than McIntosh <thanm@google.com>
src/cmd/compile/internal/noder/writer.go
test/fixedbugs/issue67190.go [new file with mode: 0644]

index fe8f8f2a351394b93f3085fb8f8198066f3bb901..8fed138a4a120290daee3525ce9905f98fb75f02 100644 (file)
@@ -1582,6 +1582,7 @@ func (w *writer) switchStmt(stmt *syntax.SwitchStmt) {
        w.stmt(stmt.Init)
 
        var iface, tagType types2.Type
+       var tagTypeIsChan bool
        if guard, ok := stmt.Tag.(*syntax.TypeSwitchGuard); w.Bool(ok) {
                iface = w.p.typeOf(guard.X)
 
@@ -1603,6 +1604,7 @@ func (w *writer) switchStmt(stmt *syntax.SwitchStmt) {
                        tv := w.p.typeAndValue(tag)
                        tagType = tv.Type
                        tagValue = tv.Value
+                       _, tagTypeIsChan = tagType.Underlying().(*types2.Chan)
                } else {
                        tagType = types2.Typ[types2.Bool]
                        tagValue = constant.MakeBool(true)
@@ -1655,12 +1657,18 @@ func (w *writer) switchStmt(stmt *syntax.SwitchStmt) {
                // have the same type. If there are any case values that can't be
                // converted to the tag value's type, then convert everything to
                // `any` instead.
-       Outer:
-               for _, clause := range stmt.Body {
-                       for _, cas := range syntax.UnpackListExpr(clause.Cases) {
-                               if casType := w.p.typeOf(cas); !types2.AssignableTo(casType, tagType) {
-                                       tagType = types2.NewInterfaceType(nil, nil)
-                                       break Outer
+               //
+               // Except that we need to keep comparisons of channel values from
+               // being wrapped in any(). See issue #67190.
+
+               if !tagTypeIsChan {
+               Outer:
+                       for _, clause := range stmt.Body {
+                               for _, cas := range syntax.UnpackListExpr(clause.Cases) {
+                                       if casType := w.p.typeOf(cas); !types2.AssignableTo(casType, tagType) {
+                                               tagType = types2.NewInterfaceType(nil, nil)
+                                               break Outer
+                                       }
                                }
                        }
                }
@@ -1696,7 +1704,11 @@ func (w *writer) switchStmt(stmt *syntax.SwitchStmt) {
                        w.Sync(pkgbits.SyncExprs)
                        w.Len(len(cases))
                        for _, cas := range cases {
-                               w.implicitConvExpr(tagType, cas)
+                               typ := tagType
+                               if tagTypeIsChan {
+                                       typ = nil
+                               }
+                               w.implicitConvExpr(typ, cas)
                        }
                }
 
diff --git a/test/fixedbugs/issue67190.go b/test/fixedbugs/issue67190.go
new file mode 100644 (file)
index 0000000..c19b248
--- /dev/null
@@ -0,0 +1,24 @@
+// run
+
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+       ch1 := make(chan struct{})
+       var ch2 <-chan struct{} = ch1
+
+       switch ch1 {
+       case ch2:
+       default:
+               panic("bad narrow case")
+       }
+
+       switch ch2 {
+       case ch1:
+       default:
+               panic("bad narrow switch")
+       }
+}