}
}
-// setResults transfers func flag results to 'fp'.
-func (ffa *funcFlagsAnalyzer) setResults(fp *FuncProps) {
+// setResults transfers func flag results to 'funcProps'.
+func (ffa *funcFlagsAnalyzer) setResults(funcProps *FuncProps) {
var rv FuncPropBits
if !ffa.noInfo && ffa.stateForList(ffa.fn.Body) == psCallsPanic {
rv = FuncPropNeverReturns
if isMainMain(ffa.fn) {
rv &^= FuncPropNeverReturns
}
- fp.Flags = rv
+ funcProps.Flags = rv
}
func (ffa *funcFlagsAnalyzer) getstate(n ir.Node) pstate {
}
}
+func (ffa *funcFlagsAnalyzer) updatestate(n ir.Node, st pstate) {
+ if _, ok := ffa.nstate[n]; !ok {
+ base.Fatalf("funcFlagsAnalyzer: fn %q internal error, expected existing setting for node:\n%+v\n", ffa.fn.Sym().Name, n)
+ } else {
+ ffa.nstate[n] = st
+ }
+}
+
func (ffa *funcFlagsAnalyzer) setstateSoft(n ir.Node, st pstate) {
ffa.nstate[n] = st
}
+func (ffa *funcFlagsAnalyzer) panicPathTable() map[ir.Node]pstate {
+ return ffa.nstate
+}
+
// blockCombine merges together states as part of a linear sequence of
// statements, where 'pred' and 'succ' are analysis results for a pair
// of consecutive statements. Examples:
}
// stateForList walks through a list of statements and computes the
-// state/diposition for the entire list as a whole.
+// state/diposition for the entire list as a whole, as well
+// as updating disposition of intermediate nodes.
func (ffa *funcFlagsAnalyzer) stateForList(list ir.Nodes) pstate {
st := psTop
- for i := range list {
+ // Walk the list backwards so that we can update the state for
+ // earlier list elements based on what we find out about their
+ // successors. Example:
+ //
+ // if ... {
+ // L10: foo()
+ // L11: <stmt>
+ // L12: panic(...)
+ // }
+ //
+ // After combining the dispositions for line 11 and 12, we want to
+ // update the state for the call at line 10 based on that combined
+ // disposition (if L11 has no path to "return", then the call at
+ // line 10 will be on a panic path).
+ for i := len(list) - 1; i >= 0; i-- {
n := list[i]
psi := ffa.getstate(n)
if debugTrace&debugTraceFuncFlags != 0 {
fmt.Fprintf(os.Stderr, "=-= %v: stateForList n=%s ps=%s\n",
ir.Line(n), n.Op().String(), psi.String())
}
- st = blockCombine(st, psi)
+ st = blockCombine(psi, st)
+ ffa.updatestate(n, st)
}
if st == psTop {
st = psNoInfo
return false
}
cx := n.(*ir.CallExpr)
- name := ir.StaticCalleeName(cx.X)
+ name := ir.StaticCalleeName(cx.Fun)
if name == nil {
return false
}
isWellKnownFunc(s, "runtime", "throw") {
return true
}
- // FIXME: consult results of flags computation for
- // previously analyzed Go functions, including props
- // read from export data for functions in other packages.
- return false
+ if funcProps := propsForFunc(name.Func); funcProps != nil {
+ if funcProps.Flags&FuncPropNeverReturns != 0 {
+ return true
+ }
+ }
+ return name.Func.NeverReturns()
}
// pessimize is called to record the fact that we saw something in the
case ir.OFALL:
// Not important.
case ir.ODCLFUNC, ir.ORECOVER, ir.OAS, ir.OAS2, ir.OAS2FUNC, ir.OASOP,
- ir.OPRINTN, ir.OPRINT, ir.OLABEL, ir.OCALLINTER, ir.ODEFER,
+ ir.OPRINTLN, ir.OPRINT, ir.OLABEL, ir.OCALLINTER, ir.ODEFER,
ir.OSEND, ir.ORECV, ir.OSELRECV2, ir.OGO, ir.OAPPEND, ir.OAS2DOTTYPE,
ir.OAS2MAPR, ir.OGETG, ir.ODELETE, ir.OINLMARK, ir.OAS2RECV,
ir.OMIN, ir.OMAX, ir.OMAKE, ir.ORECOVERFP, ir.OGETCALLERSP: