mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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:
parent
6c3d0d259f
commit
06e57e60a7
5 changed files with 91 additions and 48 deletions
|
|
@ -639,31 +639,31 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
|||
// new(T) or new(expr)
|
||||
// (no argument evaluated yet)
|
||||
arg := argList[0]
|
||||
check.exprOrType(x, arg, true)
|
||||
var T Type
|
||||
check.exprOrType(x, arg, false)
|
||||
check.exclude(x, 1<<novalue|1<<builtin)
|
||||
switch x.mode {
|
||||
case builtin:
|
||||
check.errorf(x, UncalledBuiltin, "%s must be called", x)
|
||||
x.mode = invalid
|
||||
case invalid:
|
||||
return
|
||||
case typexpr:
|
||||
// new(T)
|
||||
T = x.typ
|
||||
if !isValid(T) {
|
||||
return
|
||||
}
|
||||
check.validVarType(arg, x.typ)
|
||||
default:
|
||||
// new(expr)
|
||||
check.verifyVersionf(call.Fun, go1_26, "new(expr)")
|
||||
T = Default(x.typ)
|
||||
if T != x.typ {
|
||||
// untyped constant: check for overflow.
|
||||
check.assignment(x, T, "argument to new")
|
||||
if isUntyped(x.typ) {
|
||||
// check for overflow and untyped nil
|
||||
check.assignment(x, nil, "argument to new")
|
||||
if x.mode == invalid {
|
||||
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.typ = &Pointer{base: T}
|
||||
x.typ = NewPointer(T)
|
||||
if check.recordTypes() {
|
||||
check.recordBuiltinType(call.Fun, makeSig(x.typ, T))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -642,31 +642,31 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
// new(T) or new(expr)
|
||||
// (no argument evaluated yet)
|
||||
arg := argList[0]
|
||||
check.exprOrType(x, arg, true)
|
||||
var T Type
|
||||
check.exprOrType(x, arg, false)
|
||||
check.exclude(x, 1<<novalue|1<<builtin)
|
||||
switch x.mode {
|
||||
case builtin:
|
||||
check.errorf(x, UncalledBuiltin, "%s must be called", x)
|
||||
x.mode = invalid
|
||||
case invalid:
|
||||
return
|
||||
case typexpr:
|
||||
// new(T)
|
||||
T = x.typ
|
||||
if !isValid(T) {
|
||||
return
|
||||
}
|
||||
check.validVarType(arg, x.typ)
|
||||
default:
|
||||
// new(expr)
|
||||
check.verifyVersionf(call.Fun, go1_26, "new(expr)")
|
||||
T = Default(x.typ)
|
||||
if T != x.typ {
|
||||
// untyped constant: check for overflow.
|
||||
check.assignment(x, T, "argument to new")
|
||||
if isUntyped(x.typ) {
|
||||
// check for overflow and untyped nil
|
||||
check.assignment(x, nil, "argument to new")
|
||||
if x.mode == invalid {
|
||||
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.typ = &Pointer{base: T}
|
||||
x.typ = NewPointer(T)
|
||||
if check.recordTypes() {
|
||||
check.recordBuiltinType(call.Fun, makeSig(x.typ, T))
|
||||
}
|
||||
|
|
|
|||
40
src/internal/types/testdata/check/builtins0.go
vendored
40
src/internal/types/testdata/check/builtins0.go
vendored
|
|
@ -609,36 +609,38 @@ func min2() {
|
|||
)
|
||||
}
|
||||
|
||||
func newInvalid() {
|
||||
f2 := func() (x, y int) { return }
|
||||
|
||||
func new1() {
|
||||
_ = new() // ERROR "not enough 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 "cannot take address" */ (int)
|
||||
_ = new(int... /* ERROR "invalid use of ..." */)
|
||||
_ = new(f0 /* ERROR "f0() (no value) used as value or type" */ ())
|
||||
_ = new(len /* ERROR "len (built-in) must be called" */)
|
||||
_ = new(1 /* ERROR "argument to new (overflows)" */ << 70)
|
||||
_ = new(f2 /* ERRORx "multiple-value.*in single-value context" */ ())
|
||||
}
|
||||
|
||||
// new(T)
|
||||
func newType() {
|
||||
_ = new(struct{ x, y int })
|
||||
|
||||
p := new(float64)
|
||||
q := new(*float64)
|
||||
_ = *p == **q
|
||||
}
|
||||
|
||||
// new(expr), added in go1.26
|
||||
func newExpr() {
|
||||
f1 := func() (x []int) { return }
|
||||
func new2() {
|
||||
// new(expr), added in go1.26
|
||||
f1 := func() []int { panic(0) }
|
||||
f2 := func() (int, int) { panic(0) }
|
||||
var (
|
||||
_ *[]int = new(f1())
|
||||
_ *func() []int = new(f1)
|
||||
_ *bool = new(false)
|
||||
_ *bool = new(1 < 2)
|
||||
_ *int = new(123)
|
||||
_ *float64 = new(1.0)
|
||||
_ *uint = new(uint(3))
|
||||
|
|
@ -647,6 +649,14 @@ func newExpr() {
|
|||
_ *struct{} = new(struct{}{})
|
||||
_ *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
|
||||
_ = new(-1)
|
||||
_ = new(1 + 1)
|
||||
|
|
|
|||
7
src/internal/types/testdata/check/go1_25.go
vendored
7
src/internal/types/testdata/check/go1_25.go
vendored
|
|
@ -10,4 +10,9 @@
|
|||
|
||||
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)
|
||||
}
|
||||
|
|
|
|||
28
src/internal/types/testdata/fixedbugs/issue75986.go
vendored
Normal file
28
src/internal/types/testdata/fixedbugs/issue75986.go
vendored
Normal 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))
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue