Если у вас есть график потока управления, проверить, что функция всегда возвращает, так же просто, как проверить, что неявный возврат в конце функции недоступен.Таким образом, поскольку существует множество анализов и оптимизаций, в которых вам нужен CFG, было бы неплохо создать его.
Тем не менее, даже без графика потока управления это свойство довольно простое.проверить, предполагая некоторые общие ограничения (в частности, что вы в порядке, когда что-то вроде if(cond) return x; if(!cond) return y;
рассматривается как падение конца, даже если это эквивалентно if(cond) return x; else return y;
, что было бы допустимо).Я также предполагаю, что нет goto
, потому что вы не указали его в своем списке операторов потока управления (я не делаю предположений относительно break
и continue
, потому что они появляются только внутри циклов, и циклы не имеют значения).1008 *
Нам просто нужно рассмотреть случаи того, как будет выглядеть юридический блок (то есть тот, который всегда достигает возврата):
Таким образом, пустой блок явно не будет разрешен, потому что он не можетдостичь возврата, если он пуст.Будет разрешен блок, который непосредственно (т.е. не внутри цикла if или) содержит возврат (и если он не находится в конце блока, все после возврата в блоке будет недоступно, что также может потребоваться)превращается в ошибку или предупреждение).
Петли не имеют значения.То есть, если ваш блок содержит цикл, он все равно должен иметь возврат вне цикла, даже если цикл содержит возврат, потому что условие цикла может быть ложным, поэтому нам не нужно дажепроверь что внутри петли.Это не было бы верно для циклов do-while, но у вас их нет.
Если блок содержит непосредственно if
с else
и блоком then, и else-блок всегда достигает возврата, этот блок также всегда достигает возврата.В этом случае все после if
- else
недоступно.В противном случае if
не имеет значения, как циклы.
Так что в псевдокоде это будет:
alwaysReturns( {} ) = false
alwaysReturns( {return exp; ...rest} ) = true
alwaysReturns( { if(exp) thenBlock else elseBlock; ...rest}) =
(alwaysReturns(thenBlock) && alwaysReturns(elseBlock)) || alwaysReturns(rest)
alwaysReturns( {otherStatement; ...rest} ) = alwaysReturns(rest)