]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: fix real/imag for untyped constant arguments
authorRobert Griesemer <gri@golang.org>
Wed, 7 Jun 2017 23:22:21 +0000 (16:22 -0700)
committerRobert Griesemer <gri@golang.org>
Thu, 8 Jun 2017 17:58:26 +0000 (17:58 +0000)
Fixes #11945.
Fixes #17446.

Change-Id: Ic674f6ebc0533ab0f97c650689125994941b72e1
Reviewed-on: https://go-review.googlesource.com/45081
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/subr.go
src/cmd/compile/internal/gc/typecheck.go
test/fixedbugs/issue11945.go [new file with mode: 0644]

index 365cfad81f0fb3fe3bedbdf35ded51cdfd335729..566403bcded85544cec0d63fbadb068260165374 100644 (file)
@@ -552,19 +552,6 @@ func methtype(t *types.Type) *types.Type {
        return nil
 }
 
-func cplxsubtype(et types.EType) types.EType {
-       switch et {
-       case TCOMPLEX64:
-               return TFLOAT32
-
-       case TCOMPLEX128:
-               return TFLOAT64
-       }
-
-       Fatalf("cplxsubtype: %v\n", et)
-       return 0
-}
-
 // eqtype reports whether t1 and t2 are identical, following the spec rules.
 //
 // Any cyclic type must go through a named type, and if one is
index b3dfe9dc8cc54da66768c3c6549b4ec2525b3284..f21cc8f826b6035d38bdf1b81fce6d41f08d20c4 100644 (file)
@@ -1365,7 +1365,7 @@ OpSwitch:
                        ok = okforcap[t.Etype]
                }
                if !ok {
-                       yyerror("invalid argument %L for %v", n.Left, n.Op)
+                       yyerror("invalid argument %L for %v", l, n.Op)
                        n.Type = nil
                        return n
                }
@@ -1401,7 +1401,6 @@ OpSwitch:
                }
 
                n.Left = typecheck(n.Left, Erv)
-               n.Left = defaultlit(n.Left, nil)
                l := n.Left
                t := l.Type
                if t == nil {
@@ -1409,22 +1408,57 @@ OpSwitch:
                        return n
                }
 
-               if !t.IsComplex() {
-                       yyerror("invalid argument %L for %v", n.Left, n.Op)
+               if t.Etype != TIDEAL && !t.IsComplex() {
+                       yyerror("invalid argument %L for %v", l, n.Op)
                        n.Type = nil
                        return n
                }
-               if Isconst(l, CTCPLX) {
-                       r := n
-                       if n.Op == OREAL {
-                               n = nodfltconst(&l.Val().U.(*Mpcplx).Real)
-                       } else {
-                               n = nodfltconst(&l.Val().U.(*Mpcplx).Imag)
+
+               // if the argument is a constant, the result is a constant
+               // (any untyped numeric constant can be represented as a
+               // complex number)
+               if l.Op == OLITERAL {
+                       var re, im *Mpflt
+                       switch consttype(l) {
+                       case CTINT, CTRUNE:
+                               re = newMpflt()
+                               re.SetInt(l.Val().U.(*Mpint))
+                               // im = 0
+                       case CTFLT:
+                               re = l.Val().U.(*Mpflt)
+                               // im = 0
+                       case CTCPLX:
+                               re = &l.Val().U.(*Mpcplx).Real
+                               im = &l.Val().U.(*Mpcplx).Imag
+                       default:
+                               yyerror("invalid argument %L for %v", l, n.Op)
+                               n.Type = nil
+                               return n
                        }
-                       n.Orig = r
+                       if n.Op == OIMAG {
+                               if im == nil {
+                                       im = newMpflt()
+                               }
+                               re = im
+                       }
+                       orig := n
+                       n = nodfltconst(re)
+                       n.Orig = orig
                }
 
-               n.Type = types.Types[cplxsubtype(t.Etype)]
+               // determine result type
+               et := t.Etype
+               switch et {
+               case TIDEAL:
+                       // result is ideal
+               case TCOMPLEX64:
+                       et = TFLOAT32
+               case TCOMPLEX128:
+                       et = TFLOAT64
+               default:
+                       Fatalf("unexpected Etype: %v\n", et)
+               }
+               n.Type = types.Types[et]
                break OpSwitch
 
        case OCOMPLEX:
diff --git a/test/fixedbugs/issue11945.go b/test/fixedbugs/issue11945.go
new file mode 100644 (file)
index 0000000..510b655
--- /dev/null
@@ -0,0 +1,71 @@
+// run
+
+// 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.
+
+package main
+
+import "fmt"
+
+// issue 17446
+const (
+       _ = real(0) // from bug report
+       _ = imag(0) // from bug report
+
+       // if the arguments are untyped, the results must be untyped
+       // (and compatible with types that can represent the values)
+       _ int = real(1)
+       _ int = real('a')
+       _ int = real(2.0)
+       _ int = real(3i)
+
+       _ float32 = real(1)
+       _ float32 = real('a')
+       _ float32 = real(2.1)
+       _ float32 = real(3.2i)
+
+       _ float64 = real(1)
+       _ float64 = real('a')
+       _ float64 = real(2.1)
+       _ float64 = real(3.2i)
+
+       _ int = imag(1)
+       _ int = imag('a')
+       _ int = imag(2.1 + 3i)
+       _ int = imag(3i)
+
+       _ float32 = imag(1)
+       _ float32 = imag('a')
+       _ float32 = imag(2.1 + 3.1i)
+       _ float32 = imag(3i)
+
+       _ float64 = imag(1)
+       _ float64 = imag('a')
+       _ float64 = imag(2.1 + 3.1i)
+       _ float64 = imag(3i)
+)
+
+var tests = []struct {
+       code      string
+       got, want interface{}
+}{
+       {"real(1)", real(1), 1.0},
+       {"real('a')", real('a'), float64('a')},
+       {"real(2.0)", real(2.0), 2.0},
+       {"real(3.2i)", real(3.2i), 0.0},
+
+       {"imag(1)", imag(1), 0.0},
+       {"imag('a')", imag('a'), 0.0},
+       {"imag(2.1 + 3.1i)", imag(2.1 + 3.1i), 3.1},
+       {"imag(3i)", imag(3i), 3.0},
+}
+
+func main() {
+       // verify compile-time evaluated constant expressions
+       for _, test := range tests {
+               if test.got != test.want {
+                       panic(fmt.Sprintf("%s: %v (%T) != %v (%T)", test.code, test.got, test.got, test.want, test.want))
+               }
+       }
+}