case OIND:
Cgenr(n.Left, a, res)
- Cgen_checknil(a)
+ if !n.Left.NonNil {
+ Cgen_checknil(a)
+ } else if Debug_checknil != 0 && n.Lineno > 1 {
+ Warnl(n.Lineno, "removed nil check")
+ }
case OINDEX:
if Ctxt.Arch.Family == sys.ARM {
case OIND:
Cgen(nl, res)
- Cgen_checknil(res)
+ if !nl.NonNil {
+ Cgen_checknil(res)
+ } else if Debug_checknil != 0 && n.Lineno > 1 {
+ Warnl(n.Lineno, "removed nil check")
+ }
case ODOT:
Agen(nl, res)
case ODOTPTR:
Cgen(nl, res)
- Cgen_checknil(res)
+ if !nl.NonNil {
+ Cgen_checknil(res)
+ } else if Debug_checknil != 0 && n.Lineno > 1 {
+ Warnl(n.Lineno, "removed nil check")
+ }
if n.Xoffset != 0 {
addOffset(res, n.Xoffset)
}
case ODOTPTR:
Cgenr(n.Left, a, res)
- Cgen_checknil(a)
+ if !n.Left.NonNil {
+ Cgen_checknil(a)
+ } else if Debug_checknil != 0 && n.Lineno > 1 {
+ Warnl(n.Lineno, "removed nil check")
+ }
a.Op = OINDREG
a.Xoffset += n.Xoffset
a.Type = n.Type
if n.Assigned {
buf.WriteString(" assigned")
}
+ if n.Bounded {
+ buf.WriteString(" bounded")
+ }
+ if n.NonNil {
+ buf.WriteString(" nonnil")
+ }
if c == 0 && n.Used {
fmt.Fprintf(&buf, " used(%v)", n.Used)
return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
case OIND:
- p := s.expr(n.Left)
- s.nilCheck(p)
+ p := s.exprPtr(n.Left, false, n.Lineno)
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
case ODOT:
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
case ODOTPTR:
- p := s.expr(n.Left)
- s.nilCheck(p)
+ p := s.exprPtr(n.Left, false, n.Lineno)
p = s.newValue1I(ssa.OpOffPtr, p.Type, n.Xoffset, p)
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Elem()), a, i)
}
case OIND:
- p := s.expr(n.Left)
- if !bounded {
- s.nilCheck(p)
- }
- return p
+ return s.exprPtr(n.Left, bounded, n.Lineno)
case ODOT:
p := s.addr(n.Left, bounded)
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
case ODOTPTR:
- p := s.expr(n.Left)
- if !bounded {
- s.nilCheck(p)
- }
+ p := s.exprPtr(n.Left, bounded, n.Lineno)
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
case OCLOSUREVAR:
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset,
}
}
+// exprPtr evaluates n to a pointer and nil-checks it.
+func (s *state) exprPtr(n *Node, bounded bool, lineno int32) *ssa.Value {
+ p := s.expr(n)
+ if bounded || n.NonNil {
+ if s.f.Config.Debug_checknil() && lineno > 1 {
+ s.f.Config.Warnl(lineno, "removed nil check")
+ }
+ return p
+ }
+ s.nilCheck(p)
+ return p
+}
+
// nilCheck generates nil pointer checking code.
// Starts a new block on return, unless nil checks are disabled.
// Used only for automatically inserted nil checks,
Addable bool // addressable
Etype EType // op for OASOP, etype for OTYPE, exclam for export, 6g saved reg, ChanDir for OTCHAN
Bounded bool // bounds check unnecessary
+ NonNil bool // guaranteed to be non-nil
Class Class // PPARAM, PAUTO, PEXTERN, etc
Embedded uint8 // ODCLFIELD embedded type
Colas bool // OAS resulting from :=
if !isblank(a) {
var_ := temp(Ptrto(t.Val()))
var_.Typecheck = 1
+ var_.NonNil = true // mapaccess always returns a non-nil pointer
n.List.SetIndex(0, var_)
n = walkexpr(n, init)
init.Append(n)
n = typecheck(n, Etop)
n = walkexpr(n, init)
- // TODO: ptr is always non-nil, so disable nil check for this OIND op.
-
case ODELETE:
init.AppendNodes(&n.Ninit)
map_ := n.List.First()
// standard version takes key by reference.
// orderexpr made sure key is addressable.
key = Nod(OADDR, n.Right, nil)
-
p = "mapaccess1"
}
z := zeroaddr(w)
n = mkcall1(mapfn(p, t), Ptrto(t.Val()), init, typename(t), n.Left, key, z)
}
+ n.NonNil = true // mapaccess always returns a non-nil pointer
n = Nod(OIND, n, nil)
n.Type = t.Val()
n.Typecheck = 1
dowidth(t)
fn := syslook("newobject")
fn = substArgTypes(fn, t)
- return mkcall1(fn, Ptrto(t), nil, typename(t))
+ v := mkcall1(fn, Ptrto(t), nil, typename(t))
+ v.NonNil = true
+ return v
}
func iscallret(n *Node) bool {
package ssa
-// TODO: return value from newobject/newarray is non-nil.
-
// nilcheckelim eliminates unnecessary nil checks.
func nilcheckelim(f *Func) {
// A nil check is redundant if the same nil check was successful in a
x = y
_ = &x[9] // ERROR "removed repeated nil check"
}
+
+func m1(m map[int][80]byte) byte {
+ v := m[3] // ERROR "removed nil check"
+ return v[5]
+}
+func m2(m map[int][800]byte) byte {
+ v := m[3] // ERROR "removed nil check"
+ return v[5]
+}
+func m3(m map[int][80]byte) (byte, bool) {
+ v, ok := m[3] // ERROR "removed nil check"
+ return v[5], ok
+}
+func m4(m map[int][800]byte) (byte, bool) {
+ v, ok := m[3] // ERROR "removed nil check"
+ return v[5], ok
+}
+func p1() byte {
+ p := new([100]byte)
+ return p[5] // ERROR "removed nil check"
+}
x := *p // ERROR "removed nil check"
*q = x // ERROR "removed nil check"
}
+
+func m1(m map[int][80]byte) byte {
+ v := m[3] // ERROR "removed nil check"
+ return v[5]
+}
+func m2(m map[int][800]byte) byte {
+ v := m[3] // ERROR "removed nil check"
+ return v[5]
+}
+func m3(m map[int][80]byte) (byte, bool) {
+ v, ok := m[3] // ERROR "removed nil check"
+ return v[5], ok
+}
+func m4(m map[int][800]byte) (byte, bool) {
+ v, ok := m[3] // ERROR "removed nil check"
+ return v[5], ok
+}
+func p1() byte {
+ p := new([100]byte)
+ return p[5] // ERROR "removed nil check"
+}