mirror of
https://github.com/golang/go
synced 2024-11-11 20:20:23 -07:00
[dev.typeparams] cmd/compile/internal/types2: correct error position for inherited const init expression
Enabled fixedbugs/issue8183.go for run.go with new typechecker now that issue is fixed. Fixes #42992. Updates #42991. Change-Id: I23451999983b740d5f37ce3fa75ee756daf1a44f Reviewed-on: https://go-review.googlesource.com/c/go/+/275517 Trust: Robert Griesemer <gri@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
02820d61a9
commit
cd15a48036
@ -51,6 +51,7 @@ type context struct {
|
|||||||
scope *Scope // top-most scope for lookups
|
scope *Scope // top-most scope for lookups
|
||||||
pos syntax.Pos // if valid, identifiers are looked up as if at position pos (used by Eval)
|
pos syntax.Pos // if valid, identifiers are looked up as if at position pos (used by Eval)
|
||||||
iota constant.Value // value of iota in a constant declaration; nil otherwise
|
iota constant.Value // value of iota in a constant declaration; nil otherwise
|
||||||
|
errpos syntax.Pos // if valid, identifier position of a constant with inherited initializer
|
||||||
sig *Signature // function signature if inside a function; nil otherwise
|
sig *Signature // function signature if inside a function; nil otherwise
|
||||||
isPanic map[*syntax.CallExpr]bool // set of panic call expressions (used for termination check)
|
isPanic map[*syntax.CallExpr]bool // set of panic call expressions (used for termination check)
|
||||||
hasLabel bool // set if a function makes use of labels (only ~1% of functions); unused outside functions
|
hasLabel bool // set if a function makes use of labels (only ~1% of functions); unused outside functions
|
||||||
|
@ -187,7 +187,7 @@ func (check *Checker) objDecl(obj Object, def *Named) {
|
|||||||
switch obj := obj.(type) {
|
switch obj := obj.(type) {
|
||||||
case *Const:
|
case *Const:
|
||||||
check.decl = d // new package-level const decl
|
check.decl = d // new package-level const decl
|
||||||
check.constDecl(obj, d.vtyp, d.init)
|
check.constDecl(obj, d.vtyp, d.init, d.inherited)
|
||||||
case *Var:
|
case *Var:
|
||||||
check.decl = d // new package-level var decl
|
check.decl = d // new package-level var decl
|
||||||
check.varDecl(obj, d.lhs, d.vtyp, d.init)
|
check.varDecl(obj, d.lhs, d.vtyp, d.init)
|
||||||
@ -421,12 +421,16 @@ func firstInSrc(path []Object) int {
|
|||||||
return fst
|
return fst
|
||||||
}
|
}
|
||||||
|
|
||||||
func (check *Checker) constDecl(obj *Const, typ, init syntax.Expr) {
|
func (check *Checker) constDecl(obj *Const, typ, init syntax.Expr, inherited bool) {
|
||||||
assert(obj.typ == nil)
|
assert(obj.typ == nil)
|
||||||
|
|
||||||
// use the correct value of iota
|
// use the correct value of iota and errpos
|
||||||
defer func(iota constant.Value) { check.iota = iota }(check.iota)
|
defer func(iota constant.Value, errpos syntax.Pos) {
|
||||||
|
check.iota = iota
|
||||||
|
check.errpos = errpos
|
||||||
|
}(check.iota, check.errpos)
|
||||||
check.iota = obj.val
|
check.iota = obj.val
|
||||||
|
check.errpos = nopos
|
||||||
|
|
||||||
// provide valid constant value under all circumstances
|
// provide valid constant value under all circumstances
|
||||||
obj.val = constant.MakeUnknown()
|
obj.val = constant.MakeUnknown()
|
||||||
@ -449,6 +453,15 @@ func (check *Checker) constDecl(obj *Const, typ, init syntax.Expr) {
|
|||||||
// check initialization
|
// check initialization
|
||||||
var x operand
|
var x operand
|
||||||
if init != nil {
|
if init != nil {
|
||||||
|
if inherited {
|
||||||
|
// The initialization expression is inherited from a previous
|
||||||
|
// constant declaration, and (error) positions refer to that
|
||||||
|
// expression and not the current constant declaration. Use
|
||||||
|
// the constant identifier position for any errors during
|
||||||
|
// init expression evaluation since that is all we have
|
||||||
|
// (see issues #42991, #42992).
|
||||||
|
check.errpos = obj.pos
|
||||||
|
}
|
||||||
check.expr(&x, init)
|
check.expr(&x, init)
|
||||||
}
|
}
|
||||||
check.initConst(obj, &x)
|
check.initConst(obj, &x)
|
||||||
@ -898,7 +911,7 @@ func (check *Checker) declStmt(list []syntax.Decl) {
|
|||||||
init = values[i]
|
init = values[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
check.constDecl(obj, last.Type, init)
|
check.constDecl(obj, last.Type, init, inherited)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constants must always have init values.
|
// Constants must always have init values.
|
||||||
|
@ -87,6 +87,17 @@ func (check *Checker) err(pos syntax.Pos, msg string, soft bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we are encountering an error while evaluating an inherited
|
||||||
|
// constant initialization expression, pos is the position of in
|
||||||
|
// the original expression, and not of the currently declared
|
||||||
|
// constant identifier. Use the provided errpos instead.
|
||||||
|
// TODO(gri) We may also want to augment the error message and
|
||||||
|
// refer to the position (pos) in the original expression.
|
||||||
|
if check.errpos.IsKnown() {
|
||||||
|
assert(check.iota != nil)
|
||||||
|
pos = check.errpos
|
||||||
|
}
|
||||||
|
|
||||||
err := Error{pos, stripAnnotations(msg), msg, soft}
|
err := Error{pos, stripAnnotations(msg), msg, soft}
|
||||||
if check.firstErr == nil {
|
if check.firstErr == nil {
|
||||||
check.firstErr = err
|
check.firstErr = err
|
||||||
|
@ -17,12 +17,13 @@ import (
|
|||||||
|
|
||||||
// A declInfo describes a package-level const, type, var, or func declaration.
|
// A declInfo describes a package-level const, type, var, or func declaration.
|
||||||
type declInfo struct {
|
type declInfo struct {
|
||||||
file *Scope // scope of file containing this declaration
|
file *Scope // scope of file containing this declaration
|
||||||
lhs []*Var // lhs of n:1 variable declarations, or nil
|
lhs []*Var // lhs of n:1 variable declarations, or nil
|
||||||
vtyp syntax.Expr // type, or nil (for const and var declarations only)
|
vtyp syntax.Expr // type, or nil (for const and var declarations only)
|
||||||
init syntax.Expr // init/orig expression, or nil (for const and var declarations only)
|
init syntax.Expr // init/orig expression, or nil (for const and var declarations only)
|
||||||
tdecl *syntax.TypeDecl // type declaration, or nil
|
inherited bool // if set, the init expression is inherited from a previous constant declaration
|
||||||
fdecl *syntax.FuncDecl // func declaration, or nil
|
tdecl *syntax.TypeDecl // type declaration, or nil
|
||||||
|
fdecl *syntax.FuncDecl // func declaration, or nil
|
||||||
|
|
||||||
// The deps field tracks initialization expression dependencies.
|
// The deps field tracks initialization expression dependencies.
|
||||||
deps map[Object]bool // lazily initialized
|
deps map[Object]bool // lazily initialized
|
||||||
@ -338,7 +339,7 @@ func (check *Checker) collectObjects() {
|
|||||||
init = values[i]
|
init = values[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
d := &declInfo{file: fileScope, vtyp: last.Type, init: init}
|
d := &declInfo{file: fileScope, vtyp: last.Type, init: init, inherited: inherited}
|
||||||
check.declarePkgObj(name, obj, d)
|
check.declarePkgObj(name, obj, d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,4 +104,35 @@ func _() {
|
|||||||
const x, y, z = 0, 1, unsafe.Sizeof(func() { _ = x /* ERROR "undeclared name" */ + y /* ERROR "undeclared name" */ + z /* ERROR "undeclared name" */ })
|
const x, y, z = 0, 1, unsafe.Sizeof(func() { _ = x /* ERROR "undeclared name" */ + y /* ERROR "undeclared name" */ + z /* ERROR "undeclared name" */ })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test cases for errors in inherited constant initialization expressions.
|
||||||
|
// Errors related to inherited initialization expressions must appear at
|
||||||
|
// the constant identifier being declared, not at the original expression
|
||||||
|
// (issues #42991, #42992).
|
||||||
|
const (
|
||||||
|
_ byte = 255 + iota
|
||||||
|
/* some gap */
|
||||||
|
_ // ERROR overflows byte
|
||||||
|
/* some gap */
|
||||||
|
/* some gap */ _ /* ERROR overflows byte */; _ /* ERROR overflows byte */
|
||||||
|
/* some gap */
|
||||||
|
_ = 255 + iota
|
||||||
|
_ = byte /* ERROR overflows byte */ (255) + iota
|
||||||
|
_ /* ERROR overflows byte */
|
||||||
|
)
|
||||||
|
|
||||||
|
// Test cases from issue.
|
||||||
|
const (
|
||||||
|
ok = byte(iota + 253)
|
||||||
|
bad
|
||||||
|
barn
|
||||||
|
bard // ERROR cannot convert
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
c = len([1 - iota]int{})
|
||||||
|
d
|
||||||
|
e // ERROR invalid array length
|
||||||
|
f // ERROR invalid array length
|
||||||
|
)
|
||||||
|
|
||||||
// TODO(gri) move extra tests from testdata/const0.src into here
|
// TODO(gri) move extra tests from testdata/const0.src into here
|
||||||
|
@ -12,12 +12,12 @@ const (
|
|||||||
ok = byte(iota + 253)
|
ok = byte(iota + 253)
|
||||||
bad
|
bad
|
||||||
barn
|
barn
|
||||||
bard // ERROR "constant 256 overflows byte"
|
bard // ERROR "constant 256 overflows byte|cannot convert"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
c = len([1 - iota]int{})
|
c = len([1 - iota]int{})
|
||||||
d
|
d
|
||||||
e // ERROR "array bound must be non-negative"
|
e // ERROR "array bound must be non-negative|invalid array length"
|
||||||
f // ERROR "array bound must be non-negative"
|
f // ERROR "array bound must be non-negative|invalid array length"
|
||||||
)
|
)
|
||||||
|
@ -2132,5 +2132,4 @@ var excluded = map[string]bool{
|
|||||||
"fixedbugs/issue7746.go": true, // type-checking doesn't terminate
|
"fixedbugs/issue7746.go": true, // type-checking doesn't terminate
|
||||||
"fixedbugs/issue8501.go": true, // crashes
|
"fixedbugs/issue8501.go": true, // crashes
|
||||||
"fixedbugs/issue8507.go": true, // crashes
|
"fixedbugs/issue8507.go": true, // crashes
|
||||||
"fixedbugs/issue8183.go": true, // issue #42992
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user