cmd/compile: diagnose constant division by complex zero

When casting an ideal to complex{64,128}, for example during the
evaluation of

  var a = complex64(0) / 1e-50

we want the compiler to report a division-by-zero error if a divisor
would be zero after the cast.

We already do this for floats; for example

  var b = float32(0) / 1e-50

generates a 'division by zero' error at compile time (because
float32(1e-50) is zero, and the cast is done before performing the
division).

There's no such check in the path for complex{64,128} expressions, and
no cast is performed before the division in the evaluation of

  var a = complex64(0) / 1e-50

which compiles just fine.

This patch changes the convlit1 function so that complex ideals
components (real and imag) are correctly truncated to float{32,64}
when doing an ideal -> complex{64, 128} cast.

Fixes #11674

Change-Id: Ic5f8ee3c8cfe4c3bb0621481792c96511723d151
Reviewed-on: https://go-review.googlesource.com/37891
Run-TryBot: Alberto Donizetti <alb.donizetti@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Alberto Donizetti 2017-03-07 11:54:29 +01:00 committed by Robert Griesemer
parent 49f4b5a4f5
commit 10a200e560
4 changed files with 149 additions and 4 deletions

View file

@ -160,6 +160,37 @@ func truncfltlit(oldv *Mpflt, t *types.Type) *Mpflt {
return fv
}
// truncate Real and Imag parts of Mpcplx to 32-bit or 64-bit
// precision, according to type; return truncated value. In case of
// overflow, calls yyerror but does not truncate the input value.
func trunccmplxlit(oldv *Mpcplx, t *types.Type) *Mpcplx {
if t == nil {
return oldv
}
if overflow(Val{oldv}, t) {
// Avoid setting to Inf if there was an overflow. It's never
// useful, and it'll cause spourious and confusing 'constant Inf
// overflows float32' errors down the road.
return oldv
}
cv := newMpcmplx()
switch t.Etype {
case TCOMPLEX64:
cv.Real.SetFloat64(oldv.Real.Float32())
cv.Imag.SetFloat64(oldv.Imag.Float32())
case TCOMPLEX128:
cv.Real.SetFloat64(oldv.Real.Float64())
cv.Imag.SetFloat64(oldv.Imag.Float64())
default:
Fatalf("trunccplxlit: unexpected Etype %v", t.Etype)
}
return cv
}
// canReuseNode indicates whether it is known to be safe
// to reuse a Node.
type canReuseNode bool
@ -361,7 +392,7 @@ func convlit1(n *Node, t *types.Type, explicit bool, reuse canReuseNode) *Node {
fallthrough
case CTCPLX:
overflow(n.Val(), t)
n.SetVal(Val{trunccmplxlit(n.Val().U.(*Mpcplx), t)})
}
} else if et == types.TSTRING && (ct == CTINT || ct == CTRUNE) && explicit {
n.SetVal(tostr(n.Val()))
@ -519,21 +550,25 @@ func doesoverflow(v Val, t *types.Type) bool {
return false
}
func overflow(v Val, t *types.Type) {
func overflow(v Val, t *types.Type) bool {
// v has already been converted
// to appropriate form for t.
if t == nil || t.Etype == TIDEAL {
return
return false
}
// Only uintptrs may be converted to unsafe.Pointer, which cannot overflow.
if t.Etype == TUNSAFEPTR {
return
return false
}
if doesoverflow(v, t) {
yyerror("constant %v overflows %v", v, t)
return true
}
return false
}
func tostr(v Val) Val {