]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: don't mix internal float/complex constants of different precision
authorRobert Griesemer <gri@golang.org>
Sun, 17 Feb 2019 23:35:52 +0000 (15:35 -0800)
committerRobert Griesemer <gri@golang.org>
Tue, 19 Feb 2019 21:05:17 +0000 (21:05 +0000)
There are several places where a new (internal) complex constant is allocated
via new(Mpcplx) rather than newMpcmplx(). The problem with using new() is that
the Mpcplx data structure's Real and Imag components don't get initialized with
an Mpflt of the correct precision (they have precision 0, which may be adjusted
later).

In all cases but one, the components of those complex constants are set using
a Set operation which "inherits" the correct precision from the value that is
being set.

But when creating a complex value for an imaginary literal, the imaginary
component is set via SetString which assumes 64bits of precision by default.
As a result, the internal representation of 0.01i and complex(0, 0.01) was
not correct.

Replaced all used of new(Mpcplx) with newMpcmplx() and added a new test.

Fixes #30243.

Change-Id: Ife7fd6ccd42bf887a55c6ce91727754657e6cb2d
Reviewed-on: https://go-review.googlesource.com/c/163000
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/compile/internal/gc/const.go
src/cmd/compile/internal/gc/mpfloat.go
src/cmd/compile/internal/gc/noder.go
src/cmd/compile/internal/gc/swt_test.go
src/cmd/compile/internal/gc/typecheck.go
test/fixedbugs/issue30243.go [new file with mode: 0644]

index 3a9080e67d874d45ee21c5d0c94ccc4325d6583c..f2035bf9a865af39e80db56c454323b12c518411 100644 (file)
@@ -427,13 +427,13 @@ bad:
 func tocplx(v Val) Val {
        switch u := v.U.(type) {
        case *Mpint:
-               c := new(Mpcplx)
+               c := newMpcmplx()
                c.Real.SetInt(u)
                c.Imag.SetFloat64(0.0)
                v.U = c
 
        case *Mpflt:
-               c := new(Mpcplx)
+               c := newMpcmplx()
                c.Real.Set(u)
                c.Imag.SetFloat64(0.0)
                v.U = c
@@ -845,7 +845,7 @@ Outer:
        case CTCPLX:
                x, y := x.U.(*Mpcplx), y.U.(*Mpcplx)
 
-               u := new(Mpcplx)
+               u := newMpcmplx()
                u.Real.Set(&x.Real)
                u.Imag.Set(&x.Imag)
                switch op {
@@ -900,7 +900,7 @@ func unaryOp(op Op, x Val, t *types.Type) Val {
 
                case CTCPLX:
                        x := x.U.(*Mpcplx)
-                       u := new(Mpcplx)
+                       u := newMpcmplx()
                        u.Real.Set(&x.Real)
                        u.Imag.Set(&x.Imag)
                        u.Real.Neg()
index 846ce4cca708827cd65386180cd3062d24f24a09..b3a9af452adbfc95c6564baaa6e87424d2aa172b 100644 (file)
@@ -32,12 +32,14 @@ type Mpcplx struct {
        Imag Mpflt
 }
 
+// Use newMpflt (not new(Mpflt)!) to get the correct default precision.
 func newMpflt() *Mpflt {
        var a Mpflt
        a.Val.SetPrec(Mpprec)
        return &a
 }
 
+// Use newMpcmplx (not new(Mpcplx)!) to get the correct default precision.
 func newMpcmplx() *Mpcplx {
        var a Mpcplx
        a.Real = *newMpflt()
index 3aa303c0c1c404b90224d7b97fa210b8b5cb6b8a..3fab95b91701a089d085c1d17f49af9be0bc4f11 100644 (file)
@@ -1327,7 +1327,7 @@ func (p *noder) basicLit(lit *syntax.BasicLit) Val {
                return Val{U: x}
 
        case syntax.ImagLit:
-               x := new(Mpcplx)
+               x := newMpcmplx()
                x.Imag.SetString(strings.TrimSuffix(s, "i"))
                return Val{U: x}
 
index 74419596d2400b7648e4975eb4b6c2be957b46d2..2f73ef7b990920c8269dd653ad9688274be34500 100644 (file)
@@ -16,7 +16,7 @@ func nodrune(r rune) *Node {
 }
 
 func nodflt(f float64) *Node {
-       v := new(Mpflt)
+       v := newMpflt()
        v.SetFloat64(f)
        return nodlit(Val{v})
 }
index 63e0d782733a521afcd446cb35418c8746626cbc..e22fd6445a30f2d726b890c454be0d59ffbc51fc 100644 (file)
@@ -1589,7 +1589,7 @@ func typecheck1(n *Node, top int) (res *Node) {
 
                if l.Op == OLITERAL && r.Op == OLITERAL {
                        // make it a complex literal
-                       c := new(Mpcplx)
+                       c := newMpcmplx()
                        c.Real.Set(toflt(l.Val()).U.(*Mpflt))
                        c.Imag.Set(toflt(r.Val()).U.(*Mpflt))
                        setconst(n, Val{c})
diff --git a/test/fixedbugs/issue30243.go b/test/fixedbugs/issue30243.go
new file mode 100644 (file)
index 0000000..51fd204
--- /dev/null
@@ -0,0 +1,27 @@
+// run
+
+// Copyright 2019 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.
+
+// Compile-time constants, even if they cannot be represented
+// accurately, should remain the same in operations that don't
+// affect their values.
+
+package main
+
+import "fmt"
+
+func main() {
+       const x = 0.01
+       const xi = 0.01i
+       const xc = complex(0, x)
+
+       if imag(xi) != x {
+               fmt.Printf("FAILED: %g != %g\n", imag(xi), x)
+       }
+
+       if xi != complex(0, x) {
+               fmt.Printf("FAILED: %g != %g\n", xi, complex(0, x))
+       }
+}