From c84c4d9c5c2618838c6becf899c4f77b407d42ed Mon Sep 17 00:00:00 2001 From: Stephen Heumann Date: Sun, 2 Feb 2020 13:50:15 -0600 Subject: [PATCH] Check for non-void functions that execute to the end without returning a value. This generalizes the heuristic approach for checking whether _Noreturn functions could execute to the end of the function, extending it to apply to any function with a non-void return type. These checks use the same #pragma lint bit but give different messages depending on the situation. --- CCommon.pas | 3 ++- DAG.pas | 31 +++++++++++++++++++++---------- Parser.pas | 5 ++--- Scanner.pas | 5 +++-- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/CCommon.pas b/CCommon.pas index 1dfa3d0..9251f2e 100644 --- a/CCommon.pas +++ b/CCommon.pas @@ -92,7 +92,7 @@ const lintPrintf = $0010; {check printf/scanf format flags} lintOverflow = $0020; {check for overflows} lintC99Syntax = $0040; {check for syntax that C99 disallows} - lintNoreturn = $0080; {check for return in _Noreturn funcs} + lintReturn = $0080; {flag issues with how functions return} {bit masks for GetLInfo flags} {----------------------------} @@ -505,6 +505,7 @@ var wait: boolean; {wait for keypress after errors?} lintIsError: boolean; {treat lint messages as errors?} fIsNoreturn: boolean; {is the current function _Noreturn?} + doingMain: boolean; {are we processing the main function?} {syntactic classes of tokens} {---------------------------} diff --git a/DAG.pas b/DAG.pas index a55553e..a6a3be5 100644 --- a/DAG.pas +++ b/DAG.pas @@ -4823,9 +4823,10 @@ var end; {Generate} - procedure CheckNoreturn; + procedure CheckReturn; - { Check if a noreturn function looks like it might return. } + { Check if a noreturn function looks like it might return, } + { or if a non-void function might return with no value. } { } { This uses a heuristic of basically looking for code at the } { end of the function that would lead to it returning if } @@ -4838,17 +4839,22 @@ var var code: icptr; - begin {CheckNoreturn} + begin {CheckReturn} code := DAGhead; - while code^.opcode in [pc_nop,pc_ret,pc_lnm,dc_lab,dc_loc,pc_add] do + while code^.opcode in [pc_lnm,dc_lab,dc_loc,pc_add] do code := code^.next; while code^.opcode = pc_pop do code := code^.left; while code^.opcode = pc_bno do code := code^.right; if not (code^.opcode in [pc_fjp,pc_tjp,pc_ujp,pc_xjp,pc_cui,pc_cup,pc_tl1]) - then Error(154); - end; {CheckNoreturn} + then begin + if fIsNoreturn then + Error(154) + else + Error(155); + end; + end; {CheckReturn} procedure Push (code: icptr); @@ -4938,9 +4944,17 @@ case code^.opcode of pc_gil, pc_gli, pc_gdl, pc_gld, pc_lil, pc_lli, pc_ldl, pc_lld, pc_lad, pc_lao, pc_lca, pc_lda, pc_ldc, pc_ldo, pc_lod, pc_nop, dc_cns, dc_glb, dc_dst, pc_lnm, pc_nam, pc_nat, dc_lab, pc_add, - pc_ujp, dc_pin, pc_ent, pc_ret, dc_sym: + pc_ujp, dc_pin, pc_ent, dc_sym: Push(code); + pc_ret: + begin + if (lint & lintReturn) <> 0 then + if fIsNoreturn or ((code^.optype <> cgVoid) and not doingMain) then + CheckReturn; + Push(code); + end; + pc_cnn: begin code^.opcode := pc_cnv; @@ -4968,9 +4982,6 @@ case code^.opcode of end; dc_enp: begin - if fIsNoreturn then - if (lint & lintNoreturn) <> 0 then - CheckNoreturn; Push(code); Reverse; Generate; diff --git a/Parser.pas b/Parser.pas index 4cb72c9..eb4e0e0 100644 --- a/Parser.pas +++ b/Parser.pas @@ -151,7 +151,6 @@ type end; var - doingMain: boolean; {are we processing the main function?} firstCompoundStatement: boolean; {are we doing a function level compound statement?} fType: typePtr; {return type of the current function} isForwardDeclared: boolean; {is the field list component } @@ -739,7 +738,7 @@ var begin {ReturnStatement} if fIsNoreturn then - if (lint & lintNoreturn) <> 0 then + if (lint & lintReturn) <> 0 then Error(153); NextToken; {skip the 'return' token} if token.kind <> semicolonch then {if present, evaluate the return value} @@ -770,7 +769,7 @@ var end {if} else begin if (fType^.kind <> scalarType) or (fType^.baseType <> cgVoid) then - if (lint & lintC99Syntax) <> 0 then + if ((lint & lintC99Syntax) <> 0) or ((lint & lintReturn) <> 0) then Error(152); end; {else} Gen1(pc_ujp, returnLabel); {branch to the exit point} diff --git a/Scanner.pas b/Scanner.pas index c771d56..c43a1e8 100644 --- a/Scanner.pas +++ b/Scanner.pas @@ -183,7 +183,7 @@ const {----} defaultName = '13:ORCACDefs:Defaults.h'; {default include file name} maxErr = 10; {max errors on one line} - maxLint = 154; {maximum lint error code} + maxLint = 155; {maximum lint error code} type errorType = record {record of a single error} @@ -682,6 +682,7 @@ if list or (numErr <> 0) then begin 152: msg := @'lint: return with no value in non-void function'; 153: msg := @'lint: return statement in function declared _Noreturn'; 154: msg := @'lint: function declared _Noreturn can return or has unreachable code'; + 155: msg := @'lint: non-void function may not return a value or has unreachable code'; otherwise: Error(57); end; {case} writeln(msg^); @@ -3683,7 +3684,7 @@ lintIsError := true; {lint messages are considered errors} {error codes for lint messages} {if changed, also change maxLint} -lintErrors := [51,104,105,110,124,125,128,129,130,147,151,152,153,154]; +lintErrors := [51,104,105,110,124,125,128,129,130,147,151,152,153,154,155]; spaceStr := ' '; {strings used in stringization} quoteStr := '"';