go/types, types2: only report version errors if new(expr) is ok otherwise

If new(expr) is used before Go 1.26, don't report version errors if there
are other problems with the expression.

While at it, implement multiple missing type checks for new(expr) and
add corresponding test cases that were missed in CL 704935 (tests for
no value expressions, generic types, untyped nil).

Reorganize/rename builtins0.go tests for new to match existing test case
patterns again.

Fixes #75986.
For #45624.

Change-Id: I39e5516d3f8d191cc390a4d8b9911c312bbb177c
Reviewed-on: https://go-review.googlesource.com/c/go/+/713241
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Mark Freeman <markfreeman@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
This commit is contained in:
Robert Griesemer 2025-10-20 15:02:23 -07:00 committed by Gopher Robot
parent 6c3d0d259f
commit 06e57e60a7
5 changed files with 91 additions and 48 deletions

View file

@ -639,31 +639,31 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
// new(T) or new(expr) // new(T) or new(expr)
// (no argument evaluated yet) // (no argument evaluated yet)
arg := argList[0] arg := argList[0]
check.exprOrType(x, arg, true) check.exprOrType(x, arg, false)
var T Type check.exclude(x, 1<<novalue|1<<builtin)
switch x.mode { switch x.mode {
case builtin: case invalid:
check.errorf(x, UncalledBuiltin, "%s must be called", x) return
x.mode = invalid
case typexpr: case typexpr:
// new(T) // new(T)
T = x.typ check.validVarType(arg, x.typ)
if !isValid(T) {
return
}
default: default:
// new(expr) // new(expr)
check.verifyVersionf(call.Fun, go1_26, "new(expr)") if isUntyped(x.typ) {
T = Default(x.typ) // check for overflow and untyped nil
if T != x.typ { check.assignment(x, nil, "argument to new")
// untyped constant: check for overflow. if x.mode == invalid {
check.assignment(x, T, "argument to new") return
}
assert(isTyped(x.typ))
} }
check.validVarType(arg, T) // report version error only if there are no other errors
check.verifyVersionf(call.Fun, go1_26, "new(%s)", arg)
} }
T := x.typ
x.mode = value x.mode = value
x.typ = &Pointer{base: T} x.typ = NewPointer(T)
if check.recordTypes() { if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(x.typ, T)) check.recordBuiltinType(call.Fun, makeSig(x.typ, T))
} }

View file

@ -642,31 +642,31 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
// new(T) or new(expr) // new(T) or new(expr)
// (no argument evaluated yet) // (no argument evaluated yet)
arg := argList[0] arg := argList[0]
check.exprOrType(x, arg, true) check.exprOrType(x, arg, false)
var T Type check.exclude(x, 1<<novalue|1<<builtin)
switch x.mode { switch x.mode {
case builtin: case invalid:
check.errorf(x, UncalledBuiltin, "%s must be called", x) return
x.mode = invalid
case typexpr: case typexpr:
// new(T) // new(T)
T = x.typ check.validVarType(arg, x.typ)
if !isValid(T) {
return
}
default: default:
// new(expr) // new(expr)
check.verifyVersionf(call.Fun, go1_26, "new(expr)") if isUntyped(x.typ) {
T = Default(x.typ) // check for overflow and untyped nil
if T != x.typ { check.assignment(x, nil, "argument to new")
// untyped constant: check for overflow. if x.mode == invalid {
check.assignment(x, T, "argument to new") return
}
assert(isTyped(x.typ))
} }
check.validVarType(arg, T) // report version error only if there are no other errors
check.verifyVersionf(call.Fun, go1_26, "new(%s)", arg)
} }
T := x.typ
x.mode = value x.mode = value
x.typ = &Pointer{base: T} x.typ = NewPointer(T)
if check.recordTypes() { if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(x.typ, T)) check.recordBuiltinType(call.Fun, makeSig(x.typ, T))
} }

View file

@ -609,36 +609,38 @@ func min2() {
) )
} }
func newInvalid() {
f2 := func() (x, y int) { return }
func new1() {
_ = new() // ERROR "not enough arguments" _ = new() // ERROR "not enough arguments"
_ = new(1, 2) // ERROR "too many arguments" _ = new(1, 2) // ERROR "too many arguments"
_ = new(unsafe /* ERROR "use of package unsafe not in selector" */ )
_ = new(struct{ x, y int })
p := new(float64)
q := new(*float64)
_ = *p == **q
type G[P any] struct{}
_ = new(G[int])
_ = new(G /* ERROR "cannot use generic type G without instantiation" */ )
new /* ERROR "not used" */ (int) new /* ERROR "not used" */ (int)
_ = &new /* ERROR "cannot take address" */ (int) _ = &new /* ERROR "cannot take address" */ (int)
_ = new(int... /* ERROR "invalid use of ..." */) _ = new(int... /* ERROR "invalid use of ..." */)
_ = new(f0 /* ERROR "f0() (no value) used as value or type" */ ()) _ = new(f0 /* ERROR "f0() (no value) used as value or type" */ ())
_ = new(len /* ERROR "len (built-in) must be called" */) _ = new(len /* ERROR "len (built-in) must be called" */)
_ = new(1 /* ERROR "argument to new (overflows)" */ << 70) _ = new(1 /* ERROR "argument to new (overflows)" */ << 70)
_ = new(f2 /* ERRORx "multiple-value.*in single-value context" */ ())
} }
// new(T) func new2() {
func newType() { // new(expr), added in go1.26
_ = new(struct{ x, y int }) f1 := func() []int { panic(0) }
f2 := func() (int, int) { panic(0) }
p := new(float64)
q := new(*float64)
_ = *p == **q
}
// new(expr), added in go1.26
func newExpr() {
f1 := func() (x []int) { return }
var ( var (
_ *[]int = new(f1()) _ *[]int = new(f1())
_ *func() []int = new(f1) _ *func() []int = new(f1)
_ *bool = new(false) _ *bool = new(false)
_ *bool = new(1 < 2)
_ *int = new(123) _ *int = new(123)
_ *float64 = new(1.0) _ *float64 = new(1.0)
_ *uint = new(uint(3)) _ *uint = new(uint(3))
@ -647,6 +649,14 @@ func newExpr() {
_ *struct{} = new(struct{}{}) _ *struct{} = new(struct{}{})
_ *any = new(any) _ *any = new(any)
_ = new(f2 /* ERRORx "multiple-value.*in single-value context" */ ())
_ = new(1 << /* ERROR "constant shift overflow" */ 1000)
_ = new(1e10000 /* ERROR "cannot use 1e10000 (untyped float constant 1e+10000) as float64 value in argument to new (overflows)" */ )
_ = new(nil /* ERROR "use of untyped nil in argument to new" */ )
_ = new(comparable /* ERROR "cannot use type comparable outside a type constraint" */ )
_ = new(new /* ERROR "new (built-in) must be called" */ )
_ = new(panic /* ERROR "panic(0) (no value) used as value or type" */ (0))
// from issue 43125 // from issue 43125
_ = new(-1) _ = new(-1)
_ = new(1 + 1) _ = new(1 + 1)

View file

@ -10,4 +10,9 @@
package p package p
var _ = new /* ERROR "new(expr) requires go1.26 or later" */ (123) func f(x int) {
_ = new /* ERROR "new(123) requires go1.26 or later" */ (123)
_ = new /* ERROR "new(x) requires go1.26 or later" */ (x)
_ = new /* ERROR "new(f) requires go1.26 or later" */ (f)
_ = new /* ERROR "new(1 < 2) requires go1.26 or later" */ (1 < 2)
}

View file

@ -0,0 +1,28 @@
// -lang=go1.25
// 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 p
import "strings"
type T int
type G[P any] struct{}
var x T
// Verify that we don't get a version error when there's another error present in new(expr).
func f() {
_ = new(U /* ERROR "undefined: U" */)
_ = new(strings.BUILDER /* ERROR "undefined: strings.BUILDER (but have Builder)" */)
_ = new(T) // ok
_ = new(G[int]) // ok
_ = new(G /* ERROR "cannot use generic type G without instantiation" */)
_ = new(nil /* ERROR "use of untyped nil in argument to new" */)
_ = new(comparable /* ERROR "cannot use type comparable outside a type constraint" */)
_ = new(new /* ERROR "new (built-in) must be called" */)
_ = new(panic /* ERROR "panic(0) (no value) used as value or type" */ (0))
}