Skip to content

Commit 1602e49

Browse files
committed
cmd/compile: don't constant-fold non-Go constants in the frontend
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 <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 57c8eb9 commit 1602e49

File tree

5 files changed

+44
-6
lines changed

5 files changed

+44
-6
lines changed

src/cmd/compile/internal/gc/const.go

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,14 @@ func Isconst(n *Node, ct Ctype) bool {
584584

585585
// evconst rewrites constant expressions into OLITERAL nodes.
586586
func evconst(n *Node) {
587+
if !n.isGoConst() {
588+
// Avoid constant evaluation of things that aren't actually constants
589+
// according to the spec. See issue 24760.
590+
// The SSA backend has a more robust optimizer that will catch
591+
// all of these weird cases (like uintptr(unsafe.Pointer(uintptr(1)))).
592+
return
593+
}
594+
587595
nl, nr := n.Left, n.Right
588596

589597
// Pick off just the opcodes that can be constant evaluated.
@@ -1268,7 +1276,7 @@ func nonnegintconst(n *Node) int64 {
12681276
//
12691277
// Expressions derived from nil, like string([]byte(nil)), while they
12701278
// may be known at compile time, are not Go language constants.
1271-
// Only called for expressions known to evaluated to compile-time
1279+
// Only called for expressions known to evaluate to compile-time
12721280
// constants.
12731281
func (n *Node) isGoConst() bool {
12741282
if n.Orig != nil {
@@ -1277,7 +1285,6 @@ func (n *Node) isGoConst() bool {
12771285

12781286
switch n.Op {
12791287
case OADD,
1280-
OADDSTR,
12811288
OAND,
12821289
OANDAND,
12831290
OANDNOT,
@@ -1301,13 +1308,25 @@ func (n *Node) isGoConst() bool {
13011308
OSUB,
13021309
OXOR,
13031310
OIOTA,
1304-
OCOMPLEX,
13051311
OREAL,
13061312
OIMAG:
13071313
if n.Left.isGoConst() && (n.Right == nil || n.Right.isGoConst()) {
13081314
return true
13091315
}
13101316

1317+
case OCOMPLEX:
1318+
if n.List.Len() == 0 && n.Left.isGoConst() && n.Right.isGoConst() {
1319+
return true
1320+
}
1321+
1322+
case OADDSTR:
1323+
for _, n1 := range n.List.Slice() {
1324+
if !n1.isGoConst() {
1325+
return false
1326+
}
1327+
}
1328+
return true
1329+
13111330
case OCONV:
13121331
if okforconst[n.Type.Etype] && n.Left.isGoConst() {
13131332
return true

src/cmd/compile/internal/gc/fmt.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1400,9 +1400,16 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
14001400
}
14011401
mode.Fprintf(s, "sliceheader{%v,%v,%v}", n.Left, n.List.First(), n.List.Second())
14021402

1403-
case OCOPY, OCOMPLEX:
1403+
case OCOPY:
14041404
mode.Fprintf(s, "%#v(%v, %v)", n.Op, n.Left, n.Right)
14051405

1406+
case OCOMPLEX:
1407+
if n.List.Len() == 1 {
1408+
mode.Fprintf(s, "%#v(%v)", n.Op, n.List.First())
1409+
} else {
1410+
mode.Fprintf(s, "%#v(%v, %v)", n.Op, n.Left, n.Right)
1411+
}
1412+
14061413
case OCONV,
14071414
OCONVIFACE,
14081415
OCONVNOP,

src/cmd/compile/internal/gc/syntax.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,7 @@ const (
692692
OIOTA // iota
693693
OREAL // real(Left)
694694
OIMAG // imag(Left)
695-
OCOMPLEX // complex(Left, Right)
695+
OCOMPLEX // complex(Left, Right) or complex(List[0]) where List[0] is a 2-result function call
696696
OALIGNOF // unsafe.Alignof(Left)
697697
OOFFSETOF // unsafe.Offsetof(Left)
698698
OSIZEOF // unsafe.Sizeof(Left)

test/fixedbugs/issue17038.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66

77
package main
88

9-
const A = complex(0()) // ERROR "cannot call non-function"
9+
const A = complex(0()) // ERROR "cannot call non-function" "const initializer .* is not a constant"

test/fixedbugs/issue24760.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// compile
2+
3+
// Copyright 2018 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package p
8+
9+
import "unsafe"
10+
11+
var _ = string([]byte(nil))[0]
12+
var _ = uintptr(unsafe.Pointer(uintptr(1))) << 100

0 commit comments

Comments
 (0)