]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: ensure bloop only kept alive addressable nodes
authorCuong Manh Le <cuong.manhle.vn@gmail.com>
Mon, 1 Dec 2025 09:54:54 +0000 (16:54 +0700)
committerKeith Randall <khr@golang.org>
Wed, 3 Dec 2025 00:56:58 +0000 (16:56 -0800)
Fixes #76636

Change-Id: I881f88dbf62a901452c1d77e6ffca651451c7790
Reviewed-on: https://go-review.googlesource.com/c/go/+/725420
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
src/cmd/compile/internal/bloop/bloop.go
test/bloop.go

index 761b07abd4de6c20a9aec572c79dad5353be172a..56fe9a424d60486d4f7cc9fe469ebe7f5561b705 100644 (file)
@@ -73,6 +73,14 @@ func getNameFromNode(n ir.Node) *ir.Name {
        return nil
 }
 
+// getAddressableNameFromNode is like getNameFromNode but returns nil if the node is not addressable.
+func getAddressableNameFromNode(n ir.Node) *ir.Name {
+       if name := getNameFromNode(n); name != nil && ir.IsAddressable(name) {
+               return name
+       }
+       return nil
+}
+
 // keepAliveAt returns a statement that is either curNode, or a
 // block containing curNode followed by a call to runtime.KeepAlive for each
 // node in ns. These calls ensure that nodes in ns will be live until
@@ -94,6 +102,9 @@ func keepAliveAt(ns []ir.Node, curNode ir.Node) ir.Node {
                if n.Sym().IsBlank() {
                        continue
                }
+               if !ir.IsAddressable(n) {
+                       base.FatalfAt(n.Pos(), "keepAliveAt: node %v is not addressable", n)
+               }
                arg := ir.NewConvExpr(pos, ir.OCONV, types.Types[types.TUNSAFEPTR], typecheck.NodAddr(n))
                if !n.Type().IsInterface() {
                        srcRType0 := reflectdata.TypePtrAt(pos, n.Type())
@@ -129,7 +140,7 @@ func preserveStmt(curFn *ir.Func, stmt ir.Node) (ret ir.Node) {
        switch n := stmt.(type) {
        case *ir.AssignStmt:
                // Peel down struct and slice indexing to get the names
-               name := getNameFromNode(n.X)
+               name := getAddressableNameFromNode(n.X)
                if name != nil {
                        debugName(name, n.Pos())
                        ret = keepAliveAt([]ir.Node{name}, n)
@@ -144,7 +155,7 @@ func preserveStmt(curFn *ir.Func, stmt ir.Node) (ret ir.Node) {
        case *ir.AssignListStmt:
                ns := []ir.Node{}
                for _, lhs := range n.Lhs {
-                       name := getNameFromNode(lhs)
+                       name := getAddressableNameFromNode(lhs)
                        if name != nil {
                                debugName(name, n.Pos())
                                ns = append(ns, name)
@@ -159,7 +170,7 @@ func preserveStmt(curFn *ir.Func, stmt ir.Node) (ret ir.Node) {
                }
                ret = keepAliveAt(ns, n)
        case *ir.AssignOpStmt:
-               name := getNameFromNode(n.X)
+               name := getAddressableNameFromNode(n.X)
                if name != nil {
                        debugName(name, n.Pos())
                        ret = keepAliveAt([]ir.Node{name}, n)
@@ -206,7 +217,7 @@ func preserveStmt(curFn *ir.Func, stmt ir.Node) (ret ir.Node) {
                        argTmps := []ir.Node{}
                        names := []ir.Node{}
                        for i, a := range n.Args {
-                               if name := getNameFromNode(a); name != nil {
+                               if name := getAddressableNameFromNode(a); name != nil {
                                        // If they are name, keep them alive directly.
                                        debugName(name, n.Pos())
                                        names = append(names, name)
@@ -215,7 +226,7 @@ func preserveStmt(curFn *ir.Func, stmt ir.Node) (ret ir.Node) {
                                        s := a.(*ir.CompLitExpr)
                                        ns := []ir.Node{}
                                        for i, elem := range s.List {
-                                               if name := getNameFromNode(elem); name != nil {
+                                               if name := getAddressableNameFromNode(elem); name != nil {
                                                        debugName(name, n.Pos())
                                                        ns = append(ns, name)
                                                } else {
index fd22132dbfa7f22b5195022b7135a328c2990af6..69ae8f3b9ec8ceb2815efecd86db5fcc2099ea49 100644 (file)
@@ -25,6 +25,12 @@ func caninlineVariadic(x ...int) { // ERROR "can inline caninlineVariadic" "x do
        something = x[0]
 }
 
+func receiver(f func()) { // ERROR "can inline receiver" "f does not escape"
+       f()
+}
+
+func argument() {} // ERROR "can inline argument"
+
 func test(b *testing.B, localsink, cond int) { // ERROR ".*"
        for i := 0; i < b.N; i++ {
                caninline(1) // ERROR "inlining call to caninline"
@@ -49,5 +55,7 @@ func test(b *testing.B, localsink, cond int) { // ERROR ".*"
                {
                        caninline(1) // ERROR "inlining call to caninline" "function result will be kept alive"
                }
+
+               receiver(argument) // ERROR inlining call to receiver" "function arg will be kept alive"
        }
 }