// 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.
//
// 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 {
switch n.Op {
case OADD,
- OADDSTR,
OAND,
OANDAND,
OANDNOT,
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
}
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,
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)
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"
--- /dev/null
+// 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