]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: don't constant-fold non-Go constants in the frontend
authorKeith Randall <khr@google.com>
Mon, 26 Nov 2018 20:59:54 +0000 (12:59 -0800)
committerKeith Randall <khr@golang.org>
Mon, 26 Nov 2018 22:49:57 +0000 (22:49 +0000)
Abort evconst if its argument isn't a Go constant. The SSA backend
will do the optimizations in question later. They tend to be weird
cases, like uintptr(unsafe.Pointer(uintptr(1))).

Fix OADDSTR and OCOMPLEX cases in isGoConst.
OADDSTR has its arguments in n.List, not n.Left and n.Right.
OCOMPLEX might have a 2-result function as its arg in List[0]
(in which case it isn't a Go constant).

Fixes #24760

Change-Id: Iab312d994240d99b3f69bfb33a443607e872b01d
Reviewed-on: https://go-review.googlesource.com/c/151338
Run-TryBot: Keith Randall <khr@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/compile/internal/gc/const.go
src/cmd/compile/internal/gc/fmt.go
src/cmd/compile/internal/gc/syntax.go
test/fixedbugs/issue17038.go
test/fixedbugs/issue24760.go [new file with mode: 0644]

index 9f5afadd70dfaa9020e5398655b9c73c8376542a..afcdb95443a0b15cdd28675f349435681590935a 100644 (file)
@@ -584,6 +584,14 @@ func Isconst(n *Node, ct Ctype) bool {
 
 // evconst rewrites constant expressions into OLITERAL nodes.
 func evconst(n *Node) {
+       if !n.isGoConst() {
+               // Avoid constant evaluation of things that aren't actually constants
+               // according to the spec. See issue 24760.
+               // The SSA backend has a more robust optimizer that will catch
+               // all of these weird cases (like uintptr(unsafe.Pointer(uintptr(1)))).
+               return
+       }
+
        nl, nr := n.Left, n.Right
 
        // Pick off just the opcodes that can be constant evaluated.
@@ -1268,7 +1276,7 @@ func nonnegintconst(n *Node) int64 {
 //
 // Expressions derived from nil, like string([]byte(nil)), while they
 // may be known at compile time, are not Go language constants.
-// Only called for expressions known to evaluated to compile-time
+// Only called for expressions known to evaluate to compile-time
 // constants.
 func (n *Node) isGoConst() bool {
        if n.Orig != nil {
@@ -1277,7 +1285,6 @@ func (n *Node) isGoConst() bool {
 
        switch n.Op {
        case OADD,
-               OADDSTR,
                OAND,
                OANDAND,
                OANDNOT,
@@ -1301,13 +1308,25 @@ func (n *Node) isGoConst() bool {
                OSUB,
                OXOR,
                OIOTA,
-               OCOMPLEX,
                OREAL,
                OIMAG:
                if n.Left.isGoConst() && (n.Right == nil || n.Right.isGoConst()) {
                        return true
                }
 
+       case OCOMPLEX:
+               if n.List.Len() == 0 && n.Left.isGoConst() && n.Right.isGoConst() {
+                       return true
+               }
+
+       case OADDSTR:
+               for _, n1 := range n.List.Slice() {
+                       if !n1.isGoConst() {
+                               return false
+                       }
+               }
+               return true
+
        case OCONV:
                if okforconst[n.Type.Etype] && n.Left.isGoConst() {
                        return true
index 36f7545b3ca0f174faab219f1b57b2e5bc42f5aa..f128872dbba3b25edf848e987d54a7d08c998cd3 100644 (file)
@@ -1400,9 +1400,16 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
                }
                mode.Fprintf(s, "sliceheader{%v,%v,%v}", n.Left, n.List.First(), n.List.Second())
 
-       case OCOPY, OCOMPLEX:
+       case OCOPY:
                mode.Fprintf(s, "%#v(%v, %v)", n.Op, n.Left, n.Right)
 
+       case OCOMPLEX:
+               if n.List.Len() == 1 {
+                       mode.Fprintf(s, "%#v(%v)", n.Op, n.List.First())
+               } else {
+                       mode.Fprintf(s, "%#v(%v, %v)", n.Op, n.Left, n.Right)
+               }
+
        case OCONV,
                OCONVIFACE,
                OCONVNOP,
index 9ecea8a4c526e1218d42ce353a8f480d82254812..0be52f12719e456f4580692e1e4193f2b089801b 100644 (file)
@@ -692,7 +692,7 @@ const (
        OIOTA        // iota
        OREAL        // real(Left)
        OIMAG        // imag(Left)
-       OCOMPLEX     // complex(Left, Right)
+       OCOMPLEX     // complex(Left, Right) or complex(List[0]) where List[0] is a 2-result function call
        OALIGNOF     // unsafe.Alignof(Left)
        OOFFSETOF    // unsafe.Offsetof(Left)
        OSIZEOF      // unsafe.Sizeof(Left)
index 1b65ffc1f0eec68f2fdafe403bd64b4054368e15..e07a4b22ce25dadca544ff7e8f2443e261a7d735 100644 (file)
@@ -6,4 +6,4 @@
 
 package main
 
-const A = complex(0()) // ERROR "cannot call non-function"
+const A = complex(0()) // ERROR "cannot call non-function" "const initializer .* is not a constant"
diff --git a/test/fixedbugs/issue24760.go b/test/fixedbugs/issue24760.go
new file mode 100644 (file)
index 0000000..cd6f124
--- /dev/null
@@ -0,0 +1,12 @@
+// compile
+
+// Copyright 2018 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 p
+
+import "unsafe"
+
+var _ = string([]byte(nil))[0]
+var _ = uintptr(unsafe.Pointer(uintptr(1))) << 100