From: Alan Donovan Date: Thu, 18 Sep 2025 18:04:43 +0000 (-0400) Subject: cmd/compile/internal: support new(expr) X-Git-Tag: go1.26rc1~799 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=7bc1935db55c9d182617aba074f048f9c7573680;p=gostls13.git cmd/compile/internal: support new(expr) 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 Reviewed-by: Mateusz Poliwczak Auto-Submit: Alan Donovan LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall --- diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go index 003ec15de1..8c61bb6ed5 100644 --- a/src/cmd/compile/internal/ir/node.go +++ b/src/cmd/compile/internal/ir/node.go @@ -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 diff --git a/src/cmd/compile/internal/ir/type.go b/src/cmd/compile/internal/ir/type.go index 6daca856a6..0f44cf8d04 100644 --- a/src/cmd/compile/internal/ir/type.go +++ b/src/cmd/compile/internal/ir/type.go @@ -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 diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 45e2bfd727..ca7c6bf151 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -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? diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index 54e5f1ea5f..9c90d221c2 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -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 index 0000000000..7deffae38f --- /dev/null +++ b/test/newexpr.go @@ -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") + } + } +} diff --git a/test/used.go b/test/used.go index 516f5968a8..33e1140cef 100644 --- a/test/used.go +++ b/test/used.go @@ -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 }