mirror of https://github.com/golang/go.git
cmd/gc: accept ideal float as indices.
Fixes #4813. R=golang-dev, daniel.morsing, rsc CC=golang-dev https://golang.org/cl/7625050
This commit is contained in:
parent
5e6a1a3f48
commit
88b98ff791
|
|
@ -276,6 +276,29 @@ callrecvlist(NodeList *l)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// indexlit implements typechecking of untyped values as
|
||||||
|
// array/slice indexes. It is equivalent to defaultlit
|
||||||
|
// except for constants of numerical kind, which are acceptable
|
||||||
|
// whenever they can be represented by a value of type int.
|
||||||
|
static void
|
||||||
|
indexlit(Node **np)
|
||||||
|
{
|
||||||
|
Node *n;
|
||||||
|
|
||||||
|
n = *np;
|
||||||
|
if(n == N || !isideal(n->type))
|
||||||
|
return;
|
||||||
|
switch(consttype(n)) {
|
||||||
|
case CTINT:
|
||||||
|
case CTRUNE:
|
||||||
|
case CTFLT:
|
||||||
|
case CTCPLX:
|
||||||
|
defaultlit(np, types[TINT]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
defaultlit(np, T);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
typecheck1(Node **np, int top)
|
typecheck1(Node **np, int top)
|
||||||
{
|
{
|
||||||
|
|
@ -845,7 +868,7 @@ reswitch:
|
||||||
|
|
||||||
case TSTRING:
|
case TSTRING:
|
||||||
case TARRAY:
|
case TARRAY:
|
||||||
defaultlit(&n->right, T);
|
indexlit(&n->right);
|
||||||
if(t->etype == TSTRING)
|
if(t->etype == TSTRING)
|
||||||
n->type = types[TUINT8];
|
n->type = types[TUINT8];
|
||||||
else
|
else
|
||||||
|
|
@ -861,8 +884,8 @@ reswitch:
|
||||||
yyerror("non-integer %s index %N", why, n->right);
|
yyerror("non-integer %s index %N", why, n->right);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(n->right->op == OLITERAL) {
|
if(isconst(n->right, CTINT)) {
|
||||||
if(mpgetfix(n->right->val.u.xval) < 0)
|
if(mpgetfix(n->right->val.u.xval) < 0)
|
||||||
yyerror("invalid %s index %N (index must be non-negative)", why, n->right);
|
yyerror("invalid %s index %N (index must be non-negative)", why, n->right);
|
||||||
else if(isfixedarray(t) && t->bound > 0 && mpgetfix(n->right->val.u.xval) >= t->bound)
|
else if(isfixedarray(t) && t->bound > 0 && mpgetfix(n->right->val.u.xval) >= t->bound)
|
||||||
yyerror("invalid array index %N (out of bounds for %d-element array)", n->right, t->bound);
|
yyerror("invalid array index %N (out of bounds for %d-element array)", n->right, t->bound);
|
||||||
|
|
@ -938,8 +961,8 @@ reswitch:
|
||||||
typecheck(&n->right->left, Erv);
|
typecheck(&n->right->left, Erv);
|
||||||
typecheck(&n->right->right, Erv);
|
typecheck(&n->right->right, Erv);
|
||||||
defaultlit(&n->left, T);
|
defaultlit(&n->left, T);
|
||||||
defaultlit(&n->right->left, T);
|
indexlit(&n->right->left);
|
||||||
defaultlit(&n->right->right, T);
|
indexlit(&n->right->right);
|
||||||
l = n->left;
|
l = n->left;
|
||||||
if(isfixedarray(l->type)) {
|
if(isfixedarray(l->type)) {
|
||||||
if(!islvalue(n->left)) {
|
if(!islvalue(n->left)) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
// errorcheck
|
||||||
|
|
||||||
|
// Copyright 2013 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.
|
||||||
|
|
||||||
|
// Issue 4813: use of constant floats as indices.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
var A [3]int
|
||||||
|
var S []int
|
||||||
|
var T string
|
||||||
|
|
||||||
|
const (
|
||||||
|
i = 1
|
||||||
|
f = 2.0
|
||||||
|
f2 = 2.1
|
||||||
|
c = complex(2, 0)
|
||||||
|
c2 = complex(2, 1)
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
vf = f
|
||||||
|
vc = c
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
a1 = A[i]
|
||||||
|
a2 = A[f]
|
||||||
|
a3 = A[f2] // ERROR "truncated"
|
||||||
|
a4 = A[c]
|
||||||
|
a5 = A[c2] // ERROR "truncated"
|
||||||
|
a6 = A[vf] // ERROR "non-integer"
|
||||||
|
a7 = A[vc] // ERROR "non-integer"
|
||||||
|
|
||||||
|
s1 = S[i]
|
||||||
|
s2 = S[f]
|
||||||
|
s3 = S[f2] // ERROR "truncated"
|
||||||
|
s4 = S[c]
|
||||||
|
s5 = S[c2] // ERROR "truncated"
|
||||||
|
s6 = S[vf] // ERROR "non-integer"
|
||||||
|
s7 = S[vc] // ERROR "non-integer"
|
||||||
|
|
||||||
|
t1 = T[i]
|
||||||
|
t2 = T[f]
|
||||||
|
t3 = T[f2] // ERROR "truncated"
|
||||||
|
t4 = T[c]
|
||||||
|
t5 = T[c2] // ERROR "truncated"
|
||||||
|
t6 = T[vf] // ERROR "non-integer"
|
||||||
|
t7 = T[vc] // ERROR "non-integer"
|
||||||
|
)
|
||||||
|
|
@ -36,6 +36,8 @@ const (
|
||||||
ci64big int64 = 1<<31
|
ci64big int64 = 1<<31
|
||||||
ci64bigger int64 = 1<<32
|
ci64bigger int64 = 1<<32
|
||||||
chuge = 1<<100
|
chuge = 1<<100
|
||||||
|
cfgood = 2.0
|
||||||
|
cfbad = 2.1
|
||||||
|
|
||||||
cnj = -2
|
cnj = -2
|
||||||
cni int = -3
|
cni int = -3
|
||||||
|
|
@ -46,6 +48,8 @@ const (
|
||||||
cni64big int64 = -1<<31
|
cni64big int64 = -1<<31
|
||||||
cni64bigger int64 = -1<<32
|
cni64bigger int64 = -1<<32
|
||||||
cnhuge = -1<<100
|
cnhuge = -1<<100
|
||||||
|
cnfgood = -2.0
|
||||||
|
cnfbad = -2.1
|
||||||
)
|
)
|
||||||
|
|
||||||
var j int = 100020
|
var j int = 100020
|
||||||
|
|
@ -57,6 +61,8 @@ var i64 int64 = 100023
|
||||||
var i64big int64 = 1<<31
|
var i64big int64 = 1<<31
|
||||||
var i64bigger int64 = 1<<32
|
var i64bigger int64 = 1<<32
|
||||||
var huge uint64 = 1<<64 - 1
|
var huge uint64 = 1<<64 - 1
|
||||||
|
var fgood float64 = 2.0
|
||||||
|
var fbad float64 = 2.1
|
||||||
|
|
||||||
var nj int = -10
|
var nj int = -10
|
||||||
var ni int = -11
|
var ni int = -11
|
||||||
|
|
@ -67,6 +73,8 @@ var ni64 int64 = -13
|
||||||
var ni64big int64 = -1<<31
|
var ni64big int64 = -1<<31
|
||||||
var ni64bigger int64 = -1<<32
|
var ni64bigger int64 = -1<<32
|
||||||
var nhuge int64 = -1<<63
|
var nhuge int64 = -1<<63
|
||||||
|
var nfgood float64 = -2.0
|
||||||
|
var nfbad float64 = -2.1
|
||||||
|
|
||||||
var si []int = make([]int, 10)
|
var si []int = make([]int, 10)
|
||||||
var ai [10]int
|
var ai [10]int
|
||||||
|
|
@ -156,7 +164,7 @@ func testExpr(b *bufio.Writer, expr string) {
|
||||||
if pass == 0 {
|
if pass == 0 {
|
||||||
fmt.Fprintf(b, "\ttest(func(){use(%s)}, %q)\n", expr, expr)
|
fmt.Fprintf(b, "\ttest(func(){use(%s)}, %q)\n", expr, expr)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(b, "\tuse(%s) // ERROR \"index|overflow\"\n", expr)
|
fmt.Fprintf(b, "\tuse(%s) // ERROR \"index|overflow|truncated\"\n", expr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,15 +177,15 @@ func main() {
|
||||||
fmt.Fprint(b, "// errorcheck\n\n")
|
fmt.Fprint(b, "// errorcheck\n\n")
|
||||||
}
|
}
|
||||||
fmt.Fprint(b, prolog)
|
fmt.Fprint(b, prolog)
|
||||||
|
|
||||||
var choices = [][]string{
|
var choices = [][]string{
|
||||||
// Direct value, fetch from struct, fetch from struct pointer.
|
// Direct value, fetch from struct, fetch from struct pointer.
|
||||||
// The last two cases get us to oindex_const_sudo in gsubr.c.
|
// The last two cases get us to oindex_const_sudo in gsubr.c.
|
||||||
[]string{"", "t.", "pt."},
|
[]string{"", "t.", "pt."},
|
||||||
|
|
||||||
// Array, pointer to array, slice.
|
// Array, pointer to array, slice.
|
||||||
[]string{"a", "pa", "s"},
|
[]string{"a", "pa", "s"},
|
||||||
|
|
||||||
// Element is int, element is quad (struct).
|
// Element is int, element is quad (struct).
|
||||||
// This controls whether we end up in gsubr.c (i) or cgen.c (q).
|
// This controls whether we end up in gsubr.c (i) or cgen.c (q).
|
||||||
[]string{"i", "q"},
|
[]string{"i", "q"},
|
||||||
|
|
@ -192,9 +200,9 @@ func main() {
|
||||||
[]string{"", "n"},
|
[]string{"", "n"},
|
||||||
|
|
||||||
// Size of index.
|
// Size of index.
|
||||||
[]string{"j", "i", "i8", "i16", "i32", "i64", "i64big", "i64bigger", "huge"},
|
[]string{"j", "i", "i8", "i16", "i32", "i64", "i64big", "i64bigger", "huge", "fgood", "fbad"},
|
||||||
}
|
}
|
||||||
|
|
||||||
forall(choices, func(x []string) {
|
forall(choices, func(x []string) {
|
||||||
p, a, e, big, c, n, i := x[0], x[1], x[2], x[3], x[4], x[5], x[6]
|
p, a, e, big, c, n, i := x[0], x[1], x[2], x[3], x[4], x[5], x[6]
|
||||||
|
|
||||||
|
|
@ -206,7 +214,7 @@ func main() {
|
||||||
// negative constant
|
// negative constant
|
||||||
// large constant
|
// large constant
|
||||||
thisPass := 0
|
thisPass := 0
|
||||||
if c == "c" && (a == "a" || a == "pa" || n == "n" || i == "i64big" || i == "i64bigger" || i == "huge") {
|
if c == "c" && (a == "a" || a == "pa" || n == "n" || i == "i64big" || i == "i64bigger" || i == "huge" || i == "fbad") {
|
||||||
if i == "huge" {
|
if i == "huge" {
|
||||||
// Due to a detail of 6g's internals,
|
// Due to a detail of 6g's internals,
|
||||||
// the huge constant errors happen in an
|
// the huge constant errors happen in an
|
||||||
|
|
@ -223,27 +231,50 @@ func main() {
|
||||||
thisPass = 2
|
thisPass = 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pae := p + a + e + big
|
||||||
|
cni := c + n + i
|
||||||
|
|
||||||
// If we're using the big-len data, positive int8 and int16 cannot overflow.
|
// If we're using the big-len data, positive int8 and int16 cannot overflow.
|
||||||
if big == "b" && n == "" && (i == "i8" || i == "i16") {
|
if big == "b" && n == "" && (i == "i8" || i == "i16") {
|
||||||
|
if pass == 0 {
|
||||||
|
fmt.Fprintf(b, "\tuse(%s[%s])\n", pae, cni)
|
||||||
|
fmt.Fprintf(b, "\tuse(%s[0:%s])\n", pae, cni)
|
||||||
|
fmt.Fprintf(b, "\tuse(%s[1:%s])\n", pae, cni)
|
||||||
|
fmt.Fprintf(b, "\tuse(%s[%s:])\n", pae, cni)
|
||||||
|
fmt.Fprintf(b, "\tuse(%s[%s:%s])\n", pae, cni, cni)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float variables cannot be used as indices.
|
||||||
|
if c == "" && (i == "fgood" || i == "fbad") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Integral float constat is ok.
|
||||||
|
if c == "c" && n == "" && i == "fgood" {
|
||||||
|
if pass == 0 {
|
||||||
|
fmt.Fprintf(b, "\tuse(%s[%s])\n", pae, cni)
|
||||||
|
fmt.Fprintf(b, "\tuse(%s[0:%s])\n", pae, cni)
|
||||||
|
fmt.Fprintf(b, "\tuse(%s[1:%s])\n", pae, cni)
|
||||||
|
fmt.Fprintf(b, "\tuse(%s[%s:])\n", pae, cni)
|
||||||
|
fmt.Fprintf(b, "\tuse(%s[%s:%s])\n", pae, cni, cni)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only print the test case if it is appropriate for this pass.
|
// Only print the test case if it is appropriate for this pass.
|
||||||
if thisPass == pass {
|
if thisPass == pass {
|
||||||
pae := p+a+e+big
|
|
||||||
cni := c+n+i
|
|
||||||
|
|
||||||
// Index operation
|
// Index operation
|
||||||
testExpr(b, pae + "[" + cni + "]")
|
testExpr(b, pae+"["+cni+"]")
|
||||||
|
|
||||||
// Slice operation.
|
// Slice operation.
|
||||||
// Low index 0 is a special case in ggen.c
|
// Low index 0 is a special case in ggen.c
|
||||||
// so test both 0 and 1.
|
// so test both 0 and 1.
|
||||||
testExpr(b, pae + "[0:" + cni + "]")
|
testExpr(b, pae+"[0:"+cni+"]")
|
||||||
testExpr(b, pae + "[1:" + cni + "]")
|
testExpr(b, pae+"[1:"+cni+"]")
|
||||||
testExpr(b, pae + "[" + cni + ":]")
|
testExpr(b, pae+"["+cni+":]")
|
||||||
testExpr(b, pae + "[" + cni + ":" + cni + "]")
|
testExpr(b, pae+"["+cni+":"+cni+"]")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -253,7 +284,7 @@ func main() {
|
||||||
|
|
||||||
func forall(choices [][]string, f func([]string)) {
|
func forall(choices [][]string, f func([]string)) {
|
||||||
x := make([]string, len(choices))
|
x := make([]string, len(choices))
|
||||||
|
|
||||||
var recurse func(d int)
|
var recurse func(d int)
|
||||||
recurse = func(d int) {
|
recurse = func(d int) {
|
||||||
if d >= len(choices) {
|
if d >= len(choices) {
|
||||||
|
|
@ -261,7 +292,7 @@ func forall(choices [][]string, f func([]string)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, x[d] = range choices[d] {
|
for _, x[d] = range choices[d] {
|
||||||
recurse(d+1)
|
recurse(d + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
recurse(0)
|
recurse(0)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue