Skip to content

Commit a675e51

Browse files
committed
Make the new diagnostics actually work on do-while loops
1 parent a16b351 commit a675e51

File tree

4 files changed

+48
-34
lines changed

4 files changed

+48
-34
lines changed

source/compiler/sc.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1022,7 +1022,7 @@ SC_VDECL int pc_retexpr; /* true if the current expression is a part of a "
10221022
SC_VDECL int pc_retheap; /* heap space (in bytes) to be manually freed when returning an array returned by another function */
10231023
SC_VDECL int pc_nestlevel; /* number of active (open) compound statements */
10241024
SC_VDECL unsigned int pc_attributes;/* currently set attribute flags (for the "__pragma" operator) */
1025-
SC_VDECL int pc_loopcond; /* true if the current expression is a loop condition */
1025+
SC_VDECL int pc_loopcond; /* equals to 'tFOR', 'tWHILE' or 'tDO' if the current expression is a loop condition, zero otherwise */
10261026
SC_VDECL int pc_numloopvars; /* number of variables used inside a loop condition */
10271027

10281028
SC_VDECL constvalue_root sc_automaton_tab; /* automaton table */

source/compiler/sc1.c

+41-27
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ static void make_report(symbol *root,FILE *log,char *sourcefile);
116116
static void reduce_referrers(symbol *root);
117117
static long max_stacksize(symbol *root,int *recursion);
118118
static int testsymbols(symbol *root,int level,int testlabs,int testconst);
119-
static void scanloopvariables(symstate **loopvars);
120-
static void testloopvariables(symstate *loopvars,int line);
119+
static void scanloopvariables(symstate **loopvars,int dowhile);
120+
static void testloopvariables(symstate *loopvars,int dowhile,int line);
121121
static void destructsymbols(symbol *root,int level);
122122
static constvalue *find_constval_byval(constvalue_root *table,cell val);
123123
static symbol *fetchlab(char *name);
@@ -5177,7 +5177,7 @@ static int testsymbols(symbol *root,int level,int testlabs,int testconst)
51775177
return entry;
51785178
}
51795179

5180-
static void scanloopvariables(symstate **loopvars)
5180+
static void scanloopvariables(symstate **loopvars,int dowhile)
51815181
{
51825182
symbol *start,*sym;
51835183
int num;
@@ -5187,9 +5187,10 @@ static void scanloopvariables(symstate **loopvars)
51875187
if (sc_status!=statWRITE)
51885188
return;
51895189

5190-
/* if there's only one active loop entry (the current loop),
5191-
* then there's no enclosing loop and we have an early exit */
5192-
if (wqptr-wqSIZE==wq)
5190+
/* if there's no enclosing loop (only one active loop entry, which is the
5191+
* current loop), and the current loop is not 'do-while', then we don't need
5192+
* to memoize usage flags for local variables, so we have an early exit */
5193+
if (wqptr-wqSIZE==wq && !dowhile)
51935194
return;
51945195

51955196
/* skip labels */
@@ -5211,19 +5212,26 @@ static void scanloopvariables(symstate **loopvars)
52115212
error(103); /* insufficient memory */
52125213

52135214
for (num=0,sym=start; sym!=NULL; num++,sym=sym->next) {
5214-
/* if the variable already has the uLOOPVAR flag set (from being used
5215+
/* If the variable already has the uLOOPVAR flag set (from being used
52155216
* in an enclosing loop), we have to set the uNOLOOPVAR to exclude it
5216-
* from checks in the current loop */
5217-
if ((sym->ident==iVARIABLE || sym->ident==iREFERENCE) && (sym->usage & uLOOPVAR)!=0) {
5218-
/* ... but it might be already set from an enclosing loop,
5219-
* so we need to temporarily store it in "loopvars[num]" first */
5220-
(*loopvars)[num].usage |= (sym->usage & uNOLOOPVAR);
5221-
sym->usage |= uNOLOOPVAR;
5217+
* from checks in the current loop, ... */
5218+
if ((sym->ident==iVARIABLE || sym->ident==iREFERENCE)
5219+
&& (dowhile || (sym->usage & uLOOPVAR)!=0)) {
5220+
/* ... but it might be already set from an enclosing loop as well, so we
5221+
* have to temporarily store it in "loopvars[num]" first. Also, if this is
5222+
* a 'do-while' loop, we need to memoize and unset the 'uWRITTEN' flag, so
5223+
* later when analyzing the loop condition (which comes after the loop
5224+
* body) we'll be able to determine if the variable was modified inside
5225+
* the loop body by checking if the 'uWRITTEN' flag is set. */
5226+
(*loopvars)[num].usage |= (sym->usage & (uNOLOOPVAR | uWRITTEN));
5227+
sym->usage &= ~uWRITTEN;
5228+
if (wqptr-wqSIZE!=wq)
5229+
sym->usage |= uNOLOOPVAR;
52225230
} /* if */
52235231
} /* if */
52245232
}
52255233

5226-
static void testloopvariables(symstate *loopvars,int line)
5234+
static void testloopvariables(symstate *loopvars,int dowhile,int line)
52275235
{
52285236
symbol *start,*sym;
52295237
int num,warnnum=0;
@@ -5245,7 +5253,8 @@ static void testloopvariables(symstate *loopvars,int line)
52455253
warnnum=(pc_numloopvars==1) ? 250 : 251;
52465254
for (sym=start; sym!=NULL; sym=sym->next)
52475255
if ((sym->ident==iVARIABLE || sym->ident==iREFERENCE)
5248-
&& (sym->usage & (uLOOPVAR | uNOLOOPVAR))==uLOOPVAR)
5256+
&& (sym->usage & (uLOOPVAR | uNOLOOPVAR))==uLOOPVAR
5257+
&& (!dowhile || (sym->usage & uWRITTEN)==0))
52495258
pc_numloopvars--;
52505259
if (pc_numloopvars==0 && warnnum==251) {
52515260
errorset(sSETPOS,line);
@@ -5268,7 +5277,7 @@ static void testloopvariables(symstate *loopvars,int line)
52685277
} /* if */
52695278
sym->usage &= ~uNOLOOPVAR;
52705279
if (loopvars!=NULL)
5271-
sym->usage |= (loopvars[num].usage & uNOLOOPVAR);
5280+
sym->usage |= loopvars[num].usage;
52725281
} /* if */
52735282
} /* for */
52745283
free(loopvars);
@@ -6039,17 +6048,17 @@ static int dowhile(void)
60396048
* tiniest loop, set it below the top of the loop
60406049
*/
60416050
setline(TRUE);
6042-
scanloopvariables(&loopvars);
6051+
scanloopvariables(&loopvars,FALSE);
60436052
pc_nestlevel++; /* temporarily increase the "compound statement" nesting level,
60446053
* so any assignments made inside the loop control expression
60456054
* could be cleaned up later */
6046-
pc_loopcond=TRUE;
6055+
pc_loopcond=tWHILE;
60476056
endlessloop=test(wq[wqEXIT],TEST_DO,FALSE);/* branch to wq[wqEXIT] if false */
6048-
pc_loopcond=FALSE;
6057+
pc_loopcond=0;
60496058
pc_nestlevel--;
60506059
statement(NULL,FALSE); /* if so, do a statement */
60516060
clearassignments(pc_nestlevel+1);
6052-
testloopvariables(loopvars,loopline);
6061+
testloopvariables(loopvars,FALSE,loopline);
60536062
jumplabel(wq[wqLOOP]); /* and loop to "while" start */
60546063
setlabel(wq[wqEXIT]); /* exit label */
60556064
delwhile(); /* delete queue entry */
@@ -6067,32 +6076,37 @@ static int dowhile(void)
60676076
static int dodo(void)
60686077
{
60696078
int wq[wqSIZE],top;
6070-
int save_endlessloop,retcode;
6079+
int save_endlessloop,save_numloopvars,retcode;
60716080
int loopline=fline;
60726081
symstate *loopvars=NULL;
60736082

60746083
save_endlessloop=endlessloop;
6084+
save_numloopvars=pc_numloopvars;
6085+
pc_numloopvars=0;
60756086
addwhile(wq); /* see "dowhile" for more info */
60766087
top=getlabel(); /* make a label first */
60776088
setlabel(top); /* loop label */
6089+
scanloopvariables(&loopvars,TRUE);
60786090
statement(NULL,FALSE);
60796091
needtoken(tWHILE);
60806092
setlabel(wq[wqLOOP]); /* "continue" always jumps to WQLOOP. */
60816093
setline(TRUE);
6082-
scanloopvariables(&loopvars);
60836094
pc_nestlevel++; /* temporarily increase the "compound statement" nesting level,
60846095
* so any assignments made inside the loop control expression
60856096
* could be cleaned up later */
6097+
pc_loopcond=tDO;
60866098
endlessloop=test(wq[wqEXIT],TEST_OPT,FALSE);
6099+
pc_loopcond=0;
60876100
pc_nestlevel--;
60886101
clearassignments(pc_nestlevel+1);
6089-
testloopvariables(loopvars,loopline);
6102+
testloopvariables(loopvars,TRUE,loopline);
60906103
jumplabel(top);
60916104
setlabel(wq[wqEXIT]);
60926105
delwhile();
60936106
needtoken(tTERM);
60946107

60956108
retcode=endlessloop ? tENDLESS : tDO;
6109+
pc_numloopvars=save_numloopvars;
60966110
endlessloop=save_endlessloop;
60976111
return retcode;
60986112
}
@@ -6144,7 +6158,7 @@ static int dofor(void)
61446158
jumplabel(skiplab); /* skip expression 3 1st time */
61456159
setlabel(wq[wqLOOP]); /* "continue" goes to this label: expr3 */
61466160
setline(TRUE);
6147-
scanloopvariables(&loopvars);
6161+
scanloopvariables(&loopvars,FALSE);
61486162
/* Expressions 2 and 3 are reversed in the generated code: expression 3
61496163
* precedes expression 2. When parsing, the code is buffered and marks for
61506164
* the start of each expression are insterted in the buffer.
@@ -6159,9 +6173,9 @@ static int dofor(void)
61596173
if (matchtoken(';')) {
61606174
endlessloop=1;
61616175
} else {
6162-
pc_loopcond=TRUE;
6176+
pc_loopcond=tFOR;
61636177
endlessloop=test(wq[wqEXIT],TEST_PLAIN,FALSE);/* expression 2 (jump to wq[wqEXIT] if false) */
6164-
pc_loopcond=FALSE;
6178+
pc_loopcond=0;
61656179
needtoken(';');
61666180
} /* if */
61676181
stgmark((char)(sEXPRSTART+1)); /* mark start of 3th expression in stage */
@@ -6174,7 +6188,7 @@ static int dofor(void)
61746188
stgset(FALSE); /* stop staging */
61756189
statement(NULL,FALSE);
61766190
clearassignments(save_nestlevel+1);
6177-
testloopvariables(loopvars,loopline);
6191+
testloopvariables(loopvars,FALSE,loopline);
61786192
jumplabel(wq[wqLOOP]);
61796193
setlabel(wq[wqEXIT]);
61806194
delwhile();

source/compiler/sc2.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -3425,13 +3425,13 @@ static void markloopvariable(symbol *sym,int usage)
34253425
while (sym->parent!=NULL)
34263426
sym=sym->parent;
34273427
/* check if the variable used inside a loop condition */
3428-
if (pc_loopcond) {
3428+
if (pc_loopcond!=0) {
34293429
if (sym->vclass==sGLOBAL) {
34303430
/* stop counting variables that were used in loop condition, otherwise
34313431
* warnings 250 and 251 may be inaccurate (global variables can be
34323432
* modified from another function(s) called from the loop body, and
34333433
* currently there's no reasonable way to track this) */
3434-
pc_loopcond=FALSE;
3434+
pc_loopcond=0;
34353435
pc_numloopvars=0;
34363436
} else if ((usage & uWRITTEN)!=0) {
34373437
/* the symbol is being modified inside a loop condition before being read;

source/compiler/sc3.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -1770,10 +1770,10 @@ static int hier1(value *lval1)
17701770
error(51); /* invalid subscript, must use [ ] */
17711771
invsubscript=TRUE;
17721772
} /* if */
1773-
if (pc_loopcond) {
1773+
if (pc_loopcond!=0) {
17741774
/* stop counting variables that were used in loop condition,
17751775
* otherwise warnings 250 and 251 may be inaccurate */
1776-
pc_loopcond=FALSE;
1776+
pc_loopcond=0;
17771777
pc_numloopvars=0;
17781778
} /* if */
17791779
if (invsubscript) {
@@ -2202,10 +2202,10 @@ static int nesting=0;
22022202
error(29); /* invalid expression, assumed zero */
22032203
return;
22042204
} /* if */
2205-
if (pc_loopcond) {
2205+
if (pc_loopcond!=0) {
22062206
/* stop counting variables that were used in loop condition,
22072207
* otherwise warnings 249 and 250 may be inaccurate */
2208-
pc_loopcond=FALSE;
2208+
pc_loopcond=0;
22092209
pc_numloopvars=0;
22102210
} /* if */
22112211
/* check whether this is a function that returns an array */

0 commit comments

Comments
 (0)