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.
This commit is contained in:
Stephen Heumann 2020-02-02 13:50:15 -06:00
parent 77dcfdf3ee
commit c84c4d9c5c
4 changed files with 28 additions and 16 deletions

View File

@ -92,7 +92,7 @@ const
lintPrintf = $0010; {check printf/scanf format flags} lintPrintf = $0010; {check printf/scanf format flags}
lintOverflow = $0020; {check for overflows} lintOverflow = $0020; {check for overflows}
lintC99Syntax = $0040; {check for syntax that C99 disallows} 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} {bit masks for GetLInfo flags}
{----------------------------} {----------------------------}
@ -505,6 +505,7 @@ var
wait: boolean; {wait for keypress after errors?} wait: boolean; {wait for keypress after errors?}
lintIsError: boolean; {treat lint messages as errors?} lintIsError: boolean; {treat lint messages as errors?}
fIsNoreturn: boolean; {is the current function _Noreturn?} fIsNoreturn: boolean; {is the current function _Noreturn?}
doingMain: boolean; {are we processing the main function?}
{syntactic classes of tokens} {syntactic classes of tokens}
{---------------------------} {---------------------------}

31
DAG.pas
View File

@ -4823,9 +4823,10 @@ var
end; {Generate} 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 } { This uses a heuristic of basically looking for code at the }
{ end of the function that would lead to it returning if } { end of the function that would lead to it returning if }
@ -4838,17 +4839,22 @@ var
var var
code: icptr; code: icptr;
begin {CheckNoreturn} begin {CheckReturn}
code := DAGhead; 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; code := code^.next;
while code^.opcode = pc_pop do while code^.opcode = pc_pop do
code := code^.left; code := code^.left;
while code^.opcode = pc_bno do while code^.opcode = pc_bno do
code := code^.right; code := code^.right;
if not (code^.opcode in [pc_fjp,pc_tjp,pc_ujp,pc_xjp,pc_cui,pc_cup,pc_tl1]) if not (code^.opcode in [pc_fjp,pc_tjp,pc_ujp,pc_xjp,pc_cui,pc_cup,pc_tl1])
then Error(154); then begin
end; {CheckNoreturn} if fIsNoreturn then
Error(154)
else
Error(155);
end;
end; {CheckReturn}
procedure Push (code: icptr); 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_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, 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, 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); 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: pc_cnn:
begin begin
code^.opcode := pc_cnv; code^.opcode := pc_cnv;
@ -4968,9 +4982,6 @@ case code^.opcode of
end; end;
dc_enp: begin dc_enp: begin
if fIsNoreturn then
if (lint & lintNoreturn) <> 0 then
CheckNoreturn;
Push(code); Push(code);
Reverse; Reverse;
Generate; Generate;

View File

@ -151,7 +151,6 @@ type
end; end;
var var
doingMain: boolean; {are we processing the main function?}
firstCompoundStatement: boolean; {are we doing a function level compound statement?} firstCompoundStatement: boolean; {are we doing a function level compound statement?}
fType: typePtr; {return type of the current function} fType: typePtr; {return type of the current function}
isForwardDeclared: boolean; {is the field list component } isForwardDeclared: boolean; {is the field list component }
@ -739,7 +738,7 @@ var
begin {ReturnStatement} begin {ReturnStatement}
if fIsNoreturn then if fIsNoreturn then
if (lint & lintNoreturn) <> 0 then if (lint & lintReturn) <> 0 then
Error(153); Error(153);
NextToken; {skip the 'return' token} NextToken; {skip the 'return' token}
if token.kind <> semicolonch then {if present, evaluate the return value} if token.kind <> semicolonch then {if present, evaluate the return value}
@ -770,7 +769,7 @@ var
end {if} end {if}
else begin else begin
if (fType^.kind <> scalarType) or (fType^.baseType <> cgVoid) then 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); Error(152);
end; {else} end; {else}
Gen1(pc_ujp, returnLabel); {branch to the exit point} Gen1(pc_ujp, returnLabel); {branch to the exit point}

View File

@ -183,7 +183,7 @@ const
{----} {----}
defaultName = '13:ORCACDefs:Defaults.h'; {default include file name} defaultName = '13:ORCACDefs:Defaults.h'; {default include file name}
maxErr = 10; {max errors on one line} maxErr = 10; {max errors on one line}
maxLint = 154; {maximum lint error code} maxLint = 155; {maximum lint error code}
type type
errorType = record {record of a single error} 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'; 152: msg := @'lint: return with no value in non-void function';
153: msg := @'lint: return statement in function declared _Noreturn'; 153: msg := @'lint: return statement in function declared _Noreturn';
154: msg := @'lint: function declared _Noreturn can return or has unreachable code'; 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); otherwise: Error(57);
end; {case} end; {case}
writeln(msg^); writeln(msg^);
@ -3683,7 +3684,7 @@ lintIsError := true; {lint messages are considered errors}
{error codes for lint messages} {error codes for lint messages}
{if changed, also change maxLint} {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} spaceStr := ' '; {strings used in stringization}
quoteStr := '"'; quoteStr := '"';