]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: fix misleading "truncated to int" messages
authorAlberto Donizetti <alb.donizetti@gmail.com>
Wed, 18 Jan 2017 10:48:14 +0000 (11:48 +0100)
committerRobert Griesemer <gri@golang.org>
Tue, 7 Mar 2017 19:34:22 +0000 (19:34 +0000)
When defining an int const, the compiler tries to cast the RHS
expression to int. The cast may fail for three reasons:

  1. expr is an integer constant that overflows int
  2. expr is a floating point constant
  3. expr is a complex constant, or not a number

In the second case, in order to print a sensible error message, we
must distinguish between a floating point constant that should be
included in the error message and a floating point constant that
cannot be reasonably formatted for inclusion in an error message.

For example, in:

  const a int = 1.1
  const b int = 1 + 1e-100

a is in the former group, while b is in the latter, since the floating
point value resulting from the evaluation of the rhs of the assignment
(1.00...01) is too long to be fully printed in an error message, and
cannot be shortened without making the error message misleading
(rounding or truncating it would result in a "1", which looks like an
integer constant, and it makes little sense in an error message about
an invalid floating point expression).

To fix this problem, we try to format the float value using fconv
(which is used by the error reporting mechanism to format float
arguments), and then parse the resulting string back to a
big.Float. If the result is an integer, we assume that expr is a float
value that cannot be reasonably be formatted as a string, and we emit
an error message that does not include its string representation.

Also, change the error message for overflows to a more conservative
"integer too large", which does not mention overflows that are only
caused by an internal implementation restriction.

Also, change (*Mpint) SetFloat so that it returns a bool (instead of
0/-1 for success/failure).

Fixes #11371

Change-Id: Ibbc73e2ed2eaf41f07827b0649d0eb637150ecaa
Reviewed-on: https://go-review.googlesource.com/35411
Run-TryBot: Alberto Donizetti <alb.donizetti@gmail.com>
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/cmd/compile/internal/gc/const.go
src/cmd/compile/internal/gc/mpint.go
test/fixedbugs/issue11371.go [new file with mode: 0644]
test/fixedbugs/issue13471.go
test/fixedbugs/issue13559.go

index bd307116e804ef191fa12b2161696c1dcf2b3eea..24c0fba5231fba344f71ce7d62d01e336768d7a4 100644 (file)
@@ -6,6 +6,7 @@ package gc
 
 import (
        "cmd/internal/src"
+       "math/big"
        "strings"
 )
 
@@ -455,19 +456,33 @@ func toint(v Val) Val {
 
        case *Mpflt:
                i := new(Mpint)
-               if i.SetFloat(u) < 0 {
-                       msg := "constant %v truncated to integer"
-                       // provide better error message if SetFloat failed because f was too large
-                       if u.Val.IsInt() {
-                               msg = "constant %v overflows integer"
+               if !i.SetFloat(u) {
+                       if i.Ovf {
+                               yyerror("integer too large")
+                       } else {
+                               // The value of u cannot be represented as an integer;
+                               // so we need to print an error message.
+                               // Unfortunately some float values cannot be
+                               // reasonably formatted for inclusion in an error
+                               // message (example: 1 + 1e-100), so first we try to
+                               // format the float; if the truncation resulted in
+                               // something that looks like an integer we omit the
+                               // value from the error message.
+                               // (See issue #11371).
+                               var t big.Float
+                               t.Parse(fconv(u, FmtSharp), 10)
+                               if t.IsInt() {
+                                       yyerror("constant truncated to integer")
+                               } else {
+                                       yyerror("constant %v truncated to integer", fconv(u, FmtSharp))
+                               }
                        }
-                       yyerror(msg, fconv(u, FmtSharp))
                }
                v.U = i
 
        case *Mpcplx:
                i := new(Mpint)
-               if i.SetFloat(&u.Real) < 0 || u.Imag.CmpFloat64(0) != 0 {
+               if !i.SetFloat(&u.Real) || u.Imag.CmpFloat64(0) != 0 {
                        yyerror("constant %v%vi truncated to integer", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp|FmtSign))
                }
 
index fba82607b50ff7f937f5fe1ac32ec67dfa3eb066..f4efde3751f02ead3beca83229dcce02d7efb4ec 100644 (file)
@@ -36,15 +36,16 @@ func (a *Mpint) Set(b *Mpint) {
        a.Val.Set(&b.Val)
 }
 
-func (a *Mpint) SetFloat(b *Mpflt) int {
+func (a *Mpint) SetFloat(b *Mpflt) bool {
        // avoid converting huge floating-point numbers to integers
        // (2*Mpprec is large enough to permit all tests to pass)
        if b.Val.MantExp(nil) > 2*Mpprec {
-               return -1
+               a.SetOverflow()
+               return false
        }
 
        if _, acc := b.Val.Int(&a.Val); acc == big.Exact {
-               return 0
+               return true
        }
 
        const delta = 16 // a reasonably small number of bits > 0
@@ -55,17 +56,18 @@ func (a *Mpint) SetFloat(b *Mpflt) int {
        t.SetMode(big.ToZero)
        t.Set(&b.Val)
        if _, acc := t.Int(&a.Val); acc == big.Exact {
-               return 0
+               return true
        }
 
        // try rounding up a little
        t.SetMode(big.AwayFromZero)
        t.Set(&b.Val)
        if _, acc := t.Int(&a.Val); acc == big.Exact {
-               return 0
+               return true
        }
 
-       return -1
+       a.Ovf = false
+       return false
 }
 
 func (a *Mpint) Add(b *Mpint) {
diff --git a/test/fixedbugs/issue11371.go b/test/fixedbugs/issue11371.go
new file mode 100644 (file)
index 0000000..b2d966f
--- /dev/null
@@ -0,0 +1,17 @@
+// errorcheck
+
+// Copyright 2017 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 11371 (cmd/compile: meaningless error message "truncated to
+// integer")
+
+package issue11371
+
+const a int = 1.1        // ERROR "constant 1.1 truncated to integer"
+const b int = 1e20       // ERROR "overflows int"
+const c int = 1 + 1e-100 // ERROR "constant truncated to integer"
+const d int = 1 - 1e-100 // ERROR "constant truncated to integer"
+const e int = 1.00000001 // ERROR "constant truncated to integer"
+const f int = 0.00000001 // ERROR "constant 1e-08 truncated to integer"
index 81f034ba798ac67c99ac9ae121bff4255ad03df8..0bfed4261670384b2c693dc623e7f92754d1571c 100644 (file)
@@ -9,17 +9,17 @@
 package main
 
 func main() {
-       const _ int64 = 1e646456992 // ERROR "1e\+646456992 overflows integer"
-       const _ int32 = 1e64645699  // ERROR "1e\+64645699 overflows integer"
-       const _ int16 = 1e6464569   // ERROR "1e\+6464569 overflows integer"
-       const _ int8 = 1e646456     // ERROR "1e\+646456 overflows integer"
-       const _ int = 1e64645       // ERROR "1e\+64645 overflows integer"
+       const _ int64 = 1e646456992 // ERROR "integer too large"
+       const _ int32 = 1e64645699  // ERROR "integer too large"
+       const _ int16 = 1e6464569   // ERROR "integer too large"
+       const _ int8 = 1e646456     // ERROR "integer too large"
+       const _ int = 1e64645       // ERROR "integer too large"
 
-       const _ uint64 = 1e646456992 // ERROR "1e\+646456992 overflows integer"
-       const _ uint32 = 1e64645699  // ERROR "1e\+64645699 overflows integer"
-       const _ uint16 = 1e6464569   // ERROR "1e\+6464569 overflows integer"
-       const _ uint8 = 1e646456     // ERROR "1e\+646456 overflows integer"
-       const _ uint = 1e64645       // ERROR "1e\+64645 overflows integer"
+       const _ uint64 = 1e646456992 // ERROR "integer too large"
+       const _ uint32 = 1e64645699  // ERROR "integer too large"
+       const _ uint16 = 1e6464569   // ERROR "integer too large"
+       const _ uint8 = 1e646456     // ERROR "integer too large"
+       const _ uint = 1e64645       // ERROR "integer too large"
 
-       const _ rune = 1e64645 // ERROR "1e\+64645 overflows integer"
+       const _ rune = 1e64645 // ERROR "integer too large"
 }
index 4783c62f6870cd1ebad210bd62660e13a5701ade..16de2a2e31104d9be4715b2727a1245d93247157 100644 (file)
@@ -13,11 +13,11 @@ package p
 const _ int64 = 1e-10000 // ERROR "1e\-10000 truncated"
 
 const (
-       _ int64 = 1e10000000 // ERROR "1e\+10000000 overflows"
-       _ int64 = 1e1000000  // ERROR "1e\+1000000 overflows"
-       _ int64 = 1e100000   // ERROR "1e\+100000 overflows"
-       _ int64 = 1e10000    // ERROR "1e\+10000 overflows"
-       _ int64 = 1e1000     // ERROR "1e\+1000 overflows"
+       _ int64 = 1e10000000 // ERROR "integer too large"
+       _ int64 = 1e1000000  // ERROR "integer too large"
+       _ int64 = 1e100000   // ERROR "integer too large"
+       _ int64 = 1e10000    // ERROR "integer too large"
+       _ int64 = 1e1000     // ERROR "integer too large"
        _ int64 = 1e100      // ERROR "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 overflows"
        _ int64 = 1e10
        _ int64 = 1e1
@@ -32,11 +32,11 @@ const (
 )
 
 const (
-       _ int64 = -1e10000000 // ERROR "\-1e\+10000000 overflows"
-       _ int64 = -1e1000000  // ERROR "\-1e\+1000000 overflows"
-       _ int64 = -1e100000   // ERROR "\-1e\+100000 overflows"
-       _ int64 = -1e10000    // ERROR "\-1e\+10000 overflows"
-       _ int64 = -1e1000     // ERROR "\-1e\+1000 overflows"
+       _ int64 = -1e10000000 // ERROR "integer too large"
+       _ int64 = -1e1000000  // ERROR "integer too large"
+       _ int64 = -1e100000   // ERROR "integer too large"
+       _ int64 = -1e10000    // ERROR "integer too large"
+       _ int64 = -1e1000     // ERROR "integer too large"
        _ int64 = -1e100      // ERROR "\-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 overflows"
        _ int64 = -1e10
        _ int64 = -1e1
@@ -51,11 +51,11 @@ const (
 )
 
 const (
-       _ int64 = 1.23456789e10000000 // ERROR "1\.23457e\+10000000 overflows"
-       _ int64 = 1.23456789e1000000  // ERROR "1\.23457e\+1000000 overflows"
-       _ int64 = 1.23456789e100000   // ERROR "1\.23457e\+100000 overflows"
-       _ int64 = 1.23456789e10000    // ERROR "1\.23457e\+10000 overflows"
-       _ int64 = 1.23456789e1000     // ERROR "1\.23457e\+1000 overflows"
+       _ int64 = 1.23456789e10000000 // ERROR "integer too large"
+       _ int64 = 1.23456789e1000000  // ERROR "integer too large"
+       _ int64 = 1.23456789e100000   // ERROR "integer too large"
+       _ int64 = 1.23456789e10000    // ERROR "integer too large"
+       _ int64 = 1.23456789e1000     // ERROR "integer too large"
        _ int64 = 1.23456789e100      // ERROR "12345678900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 overflows"
        _ int64 = 1.23456789e10
        _ int64 = 1.23456789e1        // ERROR "12\.3457 truncated"
@@ -70,11 +70,11 @@ const (
 )
 
 const (
-       _ int64 = -1.23456789e10000000 // ERROR "\-1\.23457e\+10000000 overflows"
-       _ int64 = -1.23456789e1000000  // ERROR "\-1\.23457e\+1000000 overflows"
-       _ int64 = -1.23456789e100000   // ERROR "\-1\.23457e\+100000 overflows"
-       _ int64 = -1.23456789e10000    // ERROR "\-1\.23457e\+10000 overflows"
-       _ int64 = -1.23456789e1000     // ERROR "\-1\.23457e\+1000 overflows"
+       _ int64 = -1.23456789e10000000 // ERROR "integer too large"
+       _ int64 = -1.23456789e1000000  // ERROR "integer too large"
+       _ int64 = -1.23456789e100000   // ERROR "integer too large"
+       _ int64 = -1.23456789e10000    // ERROR "integer too large"
+       _ int64 = -1.23456789e1000     // ERROR "integer too large"
        _ int64 = -1.23456789e100      // ERROR "\-12345678900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 overflows"
        _ int64 = -1.23456789e10
        _ int64 = -1.23456789e1        // ERROR "\-12\.3457 truncated"