]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: simplify isGoConst
authorMatthew Dempsky <mdempsky@google.com>
Thu, 28 Feb 2019 02:18:47 +0000 (18:18 -0800)
committerMatthew Dempsky <mdempsky@google.com>
Wed, 13 Mar 2019 18:24:02 +0000 (18:24 +0000)
The only ways to construct an OLITERAL node are (1) a basic literal
from the source package, (2) constant folding within evconst (which
only folds Go language constants), (3) the universal "nil" constant,
and (4) implicit conversions of nil to some concrete type.

Passes toolstash-check.

Change-Id: I30fc6b07ebede7adbdfa4ed562436cbb7078a2ff
Reviewed-on: https://go-review.googlesource.com/c/go/+/166981
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/cmd/compile/internal/gc/const.go
src/cmd/compile/internal/gc/typecheck.go
test/fixedbugs/bug297.go
test/fixedbugs/issue11361.go
test/fixedbugs/issue17038.go
test/fixedbugs/issue8183.go

index 218d1d1d7f8a4b6a8ad769977edf2a1a9bae08da..18f8d352e91b101a45da8a0da2b3960929c3111e 100644 (file)
@@ -584,14 +584,6 @@ 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.
@@ -626,24 +618,18 @@ func evconst(n *Node) {
                }
 
        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()
@@ -657,6 +643,17 @@ func evconst(n *Node) {
                                        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, "")})
@@ -714,6 +711,10 @@ func evconst(n *Node) {
                }
 
        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()
@@ -1338,88 +1339,7 @@ func indexconst(n *Node) int64 {
 // 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 {
index 8ae6c112b60784dbef66ba64606be07e2772c26d..0efcaac2008dcd0347fca25f42c4b58a6ebbe56f 100644 (file)
@@ -3671,17 +3671,18 @@ func typecheckdef(n *Node) {
                }
 
                e = typecheck(e, ctxExpr)
-               if Isconst(e, CTNIL) {
-                       yyerrorl(n.Pos, "const initializer cannot be nil")
+               if e.Type == nil {
                        goto ret
                }
-
-               if e.Type != nil && e.Op != OLITERAL || !e.isGoConst() {
+               if !e.isGoConst() {
                        if !e.Diag() {
-                               yyerrorl(n.Pos, "const initializer %v is not a constant", e)
+                               if Isconst(e, CTNIL) {
+                                       yyerrorl(n.Pos, "const initializer cannot be nil")
+                               } else {
+                                       yyerrorl(n.Pos, "const initializer %v is not a constant", e)
+                               }
                                e.SetDiag(true)
                        }
-
                        goto ret
                }
 
index 852d208251677ff3fc6e82c93c5e13055cf6574a..c2bd253d056eac03045250d3d29fa89ba79ac2cf 100644 (file)
@@ -11,5 +11,5 @@ package main
 type ByteSize float64
 const (
        _ = iota;   // ignore first value by assigning to blank identifier
-       KB ByteSize = 1<<(10*X) // ERROR "undefined" "is not a constant|as type ByteSize"
+       KB ByteSize = 1<<(10*X) // ERROR "undefined"
 )
index d01776b47ca7a1419588bcdddc10c1be02a3f34f..1260ea89c91ebaf9205f106fe8e21ed4ac33b5fd 100644 (file)
@@ -8,4 +8,4 @@ package a
 
 import "fmt"  // ERROR "imported and not used"
 
-const n = fmt // ERROR "fmt without selector" "fmt is not a constant"
+const n = fmt // ERROR "fmt without selector"
index e07a4b22ce25dadca544ff7e8f2443e261a7d735..1b65ffc1f0eec68f2fdafe403bd64b4054368e15 100644 (file)
@@ -6,4 +6,4 @@
 
 package main
 
-const A = complex(0()) // ERROR "cannot call non-function" "const initializer .* is not a constant"
+const A = complex(0()) // ERROR "cannot call non-function"
index f23e660e9473e2045077cfd86447e76f122359e1..531dd4dbf854cb828c03467364a9a5a7a41004ee 100644 (file)
@@ -18,6 +18,6 @@ const (
 const (
        c = len([1 - iota]int{})
        d
-       e // ERROR "array bound must be non-negative" "const initializer len\(composite literal\) is not a constant"
-       f // ERROR "array bound must be non-negative" "const initializer len\(composite literal\) is not a constant"
+       e // ERROR "array bound must be non-negative"
+       f // ERROR "array bound must be non-negative"
 )