]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal: support new(expr)
authorAlan Donovan <adonovan@google.com>
Thu, 18 Sep 2025 18:04:43 +0000 (14:04 -0400)
committerGopher Robot <gobot@golang.org>
Tue, 23 Sep 2025 20:12:12 +0000 (13:12 -0700)
This CL adds compiler support for new(expr),
a feature of go1.26 that allows the user to specify
the initial value of the variable instead of its
type.

Also, a basic test of dynamic behavior.

See CL 704737 for spec change and CL 704935 for
type-checker changes.

For #45624

Change-Id: I65d27de1ee3aabb819b57cce8ea77f3073447757
Reviewed-on: https://go-review.googlesource.com/c/go/+/705157
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Mateusz Poliwczak <mpoliwczak34@gmail.com>
Auto-Submit: Alan Donovan <adonovan@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Keith Randall <khr@google.com>
src/cmd/compile/internal/ir/node.go
src/cmd/compile/internal/ir/type.go
src/cmd/compile/internal/noder/reader.go
src/cmd/compile/internal/noder/writer.go
test/newexpr.go [new file with mode: 0644]
test/used.go

index 003ec15de129e180d9713d3966eac5e7df001918..8c61bb6ed5a481e07680cf52b3831dd31dbd0844 100644 (file)
@@ -215,7 +215,7 @@ const (
        ORSH              // X >> Y
        OAND              // X & Y
        OANDNOT           // X &^ Y
-       ONEW              // new(X); corresponds to calls to new in source code
+       ONEW              // new(X); corresponds to calls to new(T) in source code
        ONOT              // !X
        OBITNOT           // ^X
        OPLUS             // +X
index 6daca856a67c1dcb49f5780f092f65e34b2d98d1..0f44cf8d04771eb97d42663f4295c2f37b63a0f6 100644 (file)
@@ -42,6 +42,10 @@ func TypeNode(t *types.Type) Node {
 
 // A DynamicType represents a type expression whose exact type must be
 // computed dynamically.
+//
+// TODO(adonovan): I think "dynamic" is a misnomer here; it's really a
+// type with free type parameters that needs to be instantiated to obtain
+// a ground type for which an rtype can exist.
 type DynamicType struct {
        miniExpr
 
index 45e2bfd727e24b2912d1e680898b7fd0ca980421..ca7c6bf1515cfa0d82310d32a39c371de25af7ad 100644 (file)
@@ -2431,8 +2431,16 @@ func (r *reader) expr() (res ir.Node) {
 
        case exprNew:
                pos := r.pos()
-               typ := r.exprType()
-               return typecheck.Expr(ir.NewUnaryExpr(pos, ir.ONEW, typ))
+               if r.Bool() {
+                       // new(expr) -> tmp := expr; &tmp
+                       x := r.expr()
+                       var init ir.Nodes
+                       addr := ir.NewAddrExpr(pos, r.tempCopy(pos, x, &init))
+                       addr.SetInit(init)
+                       return typecheck.Expr(addr)
+               }
+               // new(T)
+               return typecheck.Expr(ir.NewUnaryExpr(pos, ir.ONEW, r.exprType()))
 
        case exprSizeof:
                return ir.NewUintptr(r.pos(), r.typ().Size())
@@ -3239,6 +3247,7 @@ func (r *reader) exprType() ir.Node {
        var rtype, itab ir.Node
 
        if r.Bool() {
+               // non-empty interface
                typ, rtype, _, _, itab = r.itab(pos)
                if !typ.IsInterface() {
                        rtype = nil // TODO(mdempsky): Leave set?
index 54e5f1ea5f677f68e798ca827d55408a8feb05f2..9c90d221c28a7e8e3e3f7ffa9573ad6e384f135c 100644 (file)
@@ -2035,10 +2035,16 @@ func (w *writer) expr(expr syntax.Expr) {
                        case "new":
                                assert(len(expr.ArgList) == 1)
                                assert(!expr.HasDots)
+                               arg := expr.ArgList[0]
 
                                w.Code(exprNew)
                                w.pos(expr)
-                               w.exprType(nil, expr.ArgList[0])
+                               tv := w.p.typeAndValue(arg)
+                               if w.Bool(!tv.IsType()) {
+                                       w.expr(arg) // new(expr), go1.26
+                               } else {
+                                       w.exprType(nil, arg) // new(T)
+                               }
                                return
 
                        case "Sizeof":
diff --git a/test/newexpr.go b/test/newexpr.go
new file mode 100644 (file)
index 0000000..7deffae
--- /dev/null
@@ -0,0 +1,32 @@
+// run
+
+// Copyright 2025 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
+
+// Issue #45624 is the proposal to accept new(expr) in go1.26.
+// Here we test its run-time behavior.
+func main() {
+       {
+               p := new(123) // untyped constant expr
+               if *p != 123 {
+                       panic("wrong value")
+               }
+       }
+       {
+               x := 42
+               p := new(x) // non-constant expr
+               if *p != x {
+                       panic("wrong value")
+               }
+       }
+       {
+               x := [2]int{123, 456}
+               p := new(x) // composite value
+               if *p != x {
+                       panic("wrong value")
+               }
+       }
+}
index 516f5968a84110dedc779d4ca4aab6f516aa0b6e..33e1140cef74ac9c99f82c282e4a52efc503fec0 100644 (file)
@@ -140,6 +140,5 @@ func _() {
        _ = int                // ERROR "type int is not an expression|not an expression"
        (x)                    // ERROR "x .* not used|not used"
        _ = new(len)           // ERROR "len.*must be called"
-       // Disabled due to issue #43125.
-       // _ = new(1 + 1)         // DISABLED "1 \+ 1 is not a type"
+       _ = new(1 + 1)         // ok
 }