f.Warnl(v.Pos, "removed nil check")
}
// For bug 33724, policy is that we might choose to bump an existing position
- // off the faulting load/store in favor of the one from the nil check.
+ // off the faulting load in favor of the one from the nil check.
// Iteration order means that first nilcheck in the chain wins, others
// are bumped into the ordinary statement preservation algorithm.
u := b.Values[unnecessary.get(v.Args[0].ID)]
- if !u.Pos.SameFileAndLine(v.Pos) {
+ if !u.Type.IsMemory() && !u.Pos.SameFileAndLine(v.Pos) {
if u.Pos.IsStmt() == src.PosIsStmt {
pendingLines.add(u.Pos)
}
import (
"cmd/compile/internal/syntax"
+ "go/constant"
"internal/buildcfg"
. "internal/types/errors"
)
func (check *Checker) rangeStmt(inner stmtContext, rangeStmt *syntax.ForStmt, noNewVarPos poser, sKey, sValue, sExtra, rangeVar syntax.Expr, isDef bool) {
// check expression to iterate over
var x operand
+
+ // From the spec:
+ // The range expression x is evaluated before beginning the loop,
+ // with one exception: if at most one iteration variable is present
+ // and x or len(x) is constant, the range expression is not evaluated.
+ // So we have to be careful not to evaluate the arg in the
+ // described situation.
+
+ check.hasCallOrRecv = false
check.expr(nil, &x, rangeVar)
+ if isTypes2 && x.mode != invalid && sValue == nil && !check.hasCallOrRecv {
+ if t, ok := arrayPtrDeref(under(x.typ)).(*Array); ok {
+ // Override type of rangeVar to be a constant
+ // (and thus side-effects will not be computed
+ // by the backend).
+ check.record(&operand{
+ mode: constant_,
+ expr: rangeVar,
+ typ: Typ[Int],
+ val: constant.MakeInt64(t.len),
+ id: x.id,
+ })
+ }
+ }
+
// determine key/value types
var key, val Type
if x.mode != invalid {
package walk
import (
+ "go/constant"
"internal/buildcfg"
"unicode/utf8"
base.Fatalf("walkRange")
case types.IsInt[k]:
+ if nn := arrayRangeClear(nrange, v1, v2, a); nn != nil {
+ base.Pos = lno
+ return nn
+ }
hv1 := typecheck.TempAt(base.Pos, ir.CurFunc, t)
hn := typecheck.TempAt(base.Pos, ir.CurFunc, t)
}
lhs := stmt.X.(*ir.IndexExpr)
x := lhs.X
- if a.Type().IsPtr() && a.Type().Elem().IsArray() {
- if s, ok := x.(*ir.StarExpr); ok && s.Op() == ir.ODEREF {
- x = s.X
+
+ // Get constant number of iterations for int and array cases.
+ n := int64(-1)
+ if ir.IsConst(a, constant.Int) {
+ n = ir.Int64Val(a)
+ } else if a.Type().IsArray() {
+ n = a.Type().NumElem()
+ } else if a.Type().IsPtr() && a.Type().Elem().IsArray() {
+ n = a.Type().Elem().NumElem()
+ }
+
+ if n >= 0 {
+ // Int/Array case.
+ if !x.Type().IsArray() {
+ return nil
+ }
+ if x.Type().NumElem() != n {
+ return nil
+ }
+ } else {
+ // Slice case.
+ if !ir.SameSafeExpr(x, a) {
+ return nil
}
}
- if !ir.SameSafeExpr(x, a) || !ir.SameSafeExpr(lhs.Index, v1) {
+ if !ir.SameSafeExpr(lhs.Index, v1) {
return nil
}
return nil
}
- return arrayClear(stmt.Pos(), a, loop)
+ return arrayClear(stmt.Pos(), x, loop)
}
// arrayClear constructs a call to runtime.memclr for fast zeroing of slices and arrays.
import (
"go/ast"
+ "go/constant"
"internal/buildcfg"
. "internal/types/errors"
)
func (check *Checker) rangeStmt(inner stmtContext, rangeStmt *ast.RangeStmt, noNewVarPos positioner, sKey, sValue, sExtra, rangeVar ast.Expr, isDef bool) {
// check expression to iterate over
var x operand
+
+ // From the spec:
+ // The range expression x is evaluated before beginning the loop,
+ // with one exception: if at most one iteration variable is present
+ // and x or len(x) is constant, the range expression is not evaluated.
+ // So we have to be careful not to evaluate the arg in the
+ // described situation.
+
+ check.hasCallOrRecv = false
check.expr(nil, &x, rangeVar)
+ if isTypes2 && x.mode != invalid && sValue == nil && !check.hasCallOrRecv {
+ if t, ok := arrayPtrDeref(under(x.typ)).(*Array); ok {
+ // Override type of rangeVar to be a constant
+ // (and thus side-effects will not be computed
+ // by the backend).
+ check.record(&operand{
+ mode: constant_,
+ expr: rangeVar,
+ typ: Typ[Int],
+ val: constant.MakeInt64(t.len),
+ id: x.id,
+ })
+ }
+ }
+
// determine key/value types
var key, val Type
if x.mode != invalid {
type T struct {
a *[10]int
b [10]int
+ s []int
}
func (t *T) f() {
for i := range *t.a {
(*t.a)[i] = 0
}
+
+ // amd64:-".*runtime.memclrNoHeapPointers"
+ // amd64:"DUFFZERO"
+ for i := range t.b {
+ t.b[i] = 0
+ }
+
+ // amd64:".*runtime.memclrNoHeapPointers"
+ for i := range t.s {
+ t.s[i] = 0
+ }
}