// 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.
}
case OCONV:
- if n.Type != nil && okforconst[n.Type.Etype] && nl.Op == OLITERAL {
+ if okforconst[n.Type.Etype] && nl.Op == OLITERAL {
// TODO(mdempsky): There should be a convval function.
setconst(n, convlit1(nl, n.Type, true, false).Val())
}
case OCONVNOP:
- if nl.Op == OLITERAL && nl.isGoConst() {
+ if okforconst[n.Type.Etype] && nl.Op == OLITERAL {
// set so n.Orig gets OCONV instead of OCONVNOP
n.Op = OCONV
setconst(n, nl.Val())
}
- case OBYTES2STR:
- // string([]byte(nil)) or string([]rune(nil))
- if nl.Op == OLITERAL && nl.Val().Ctype() == CTNIL {
- setconst(n, Val{U: ""})
- }
-
case OADDSTR:
// Merge adjacent constants in the argument list.
s := n.List.Slice()
i2++
}
+ // Hack to appease toolstash. Because
+ // we were checking isGoConst early
+ // on, we wouldn't collapse adjacent
+ // string constants unless the entire
+ // string was a constant.
+ //
+ // TODO(mdempsky): Remove in next commit.
+ if i1 != 0 || i2 != len(s) {
+ return
+ }
+
nl := *s[i1]
nl.Orig = &nl
nl.SetVal(Val{strings.Join(strs, "")})
}
case OCOMPLEX:
+ if nl == nil || nr == nil {
+ // TODO(mdempsky): Remove after early OAS2FUNC rewrite CL lands.
+ break
+ }
if nl.Op == OLITERAL && nr.Op == OLITERAL {
// make it a complex literal
c := newMpcmplx()
// Expressions derived from nil, like string([]byte(nil)), while they
// may be known at compile time, are not Go language constants.
func (n *Node) isGoConst() bool {
- if n.Orig != nil {
- n = n.Orig
- }
-
- switch n.Op {
- case OADD,
- OAND,
- OANDAND,
- OANDNOT,
- OBITNOT,
- ODIV,
- OEQ,
- OGE,
- OGT,
- OLE,
- OLSH,
- OLT,
- ONEG,
- OMOD,
- OMUL,
- ONE,
- ONOT,
- OOR,
- OOROR,
- OPLUS,
- ORSH,
- OSUB,
- OXOR,
- OIOTA,
- 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, OCONVNOP:
- if okforconst[n.Type.Etype] && n.Left.isGoConst() {
- return true
- }
-
- case OLEN, OCAP:
- l := n.Left
- if l.isGoConst() {
- return true
- }
-
- // Special case: len/cap is constant when applied to array or
- // pointer to array when the expression does not contain
- // function calls or channel receive operations.
- t := l.Type
-
- if t != nil && t.IsPtr() {
- t = t.Elem()
- }
- if t != nil && t.IsArray() && !hascallchan(l) {
- return true
- }
-
- case OLITERAL:
- if n.Val().Ctype() != CTNIL {
- return true
- }
-
- case OALIGNOF, OOFFSETOF, OSIZEOF:
- return true
- }
-
- //dump("nonconst", n);
- return false
+ return n.Op == OLITERAL && n.Val().Ctype() != CTNIL
}
func hascallchan(n *Node) bool {