@@ -116,6 +116,8 @@ static void make_report(symbol *root,FILE *log,char *sourcefile);
116
116
static void reduce_referrers (symbol * root );
117
117
static long max_stacksize (symbol * root ,int * recursion );
118
118
static int testsymbols (symbol * root ,int level ,int testlabs ,int testconst );
119
+ static void scanloopvariables (symstate * * loopvars ,int dowhile );
120
+ static void testloopvariables (symstate * loopvars ,int dowhile ,int line );
119
121
static void destructsymbols (symbol * root ,int level );
120
122
static constvalue * find_constval_byval (constvalue_root * table ,cell val );
121
123
static symbol * fetchlab (char * name );
@@ -919,6 +921,7 @@ static void resetglobals(void)
919
921
pc_naked = FALSE;
920
922
pc_retexpr = FALSE;
921
923
pc_attributes = 0 ;
924
+ pc_loopcond = 0 ;
922
925
emit_flags = 0 ;
923
926
emit_stgbuf_idx = -1 ;
924
927
}
@@ -5173,6 +5176,112 @@ static int testsymbols(symbol *root,int level,int testlabs,int testconst)
5173
5176
return entry ;
5174
5177
}
5175
5178
5179
+ static void scanloopvariables (symstate * * loopvars ,int dowhile )
5180
+ {
5181
+ symbol * start ,* sym ;
5182
+ int num ;
5183
+
5184
+ /* error messages are only printed on the "writing" pass,
5185
+ * so if we are not writing yet, then we have a quick exit */
5186
+ if (sc_status != statWRITE )
5187
+ return ;
5188
+
5189
+ /* if there's no enclosing loop (only one active loop entry, which is the
5190
+ * current loop), and the current loop is not 'do-while', then we don't need
5191
+ * to memoize usage flags for local variables, so we have an early exit */
5192
+ if (wqptr - wqSIZE == wq && !dowhile )
5193
+ return ;
5194
+
5195
+ /* skip labels */
5196
+ start = & loctab ;
5197
+ while ((start = start -> next )!= NULL && start -> ident == iLABEL )
5198
+ /* nothing */ ;
5199
+ /* if there are no other local symbols, we have an early exit */
5200
+ if (start == NULL )
5201
+ return ;
5202
+
5203
+ /* count the number of local symbols */
5204
+ for (num = 0 ,sym = start ; sym != NULL ; num ++ ,sym = sym -> next )
5205
+ /* nothing */ ;
5206
+
5207
+ assert (* loopvars == NULL );
5208
+ assert (num != 0 );
5209
+ * loopvars = (symstate * )calloc ((size_t )num ,sizeof (symstate ));
5210
+ if (* loopvars == NULL )
5211
+ error (103 ); /* insufficient memory */
5212
+
5213
+ 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
+ * 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 )
5218
+ && (dowhile || (sym -> usage & uLOOPVAR )!= 0 )) {
5219
+ /* ... but it might be already set from an enclosing loop as well, so we
5220
+ * have to temporarily store it in "loopvars[num]" first. Also, if this is
5221
+ * a 'do-while' loop, we need to memoize and unset the 'uWRITTEN' flag, so
5222
+ * later when analyzing the loop condition (which comes after the loop
5223
+ * body) we'll be able to determine if the variable was modified inside
5224
+ * the loop body by checking if the 'uWRITTEN' flag is set. */
5225
+ (* loopvars )[num ].usage |= (sym -> usage & (uNOLOOPVAR | uWRITTEN ));
5226
+ sym -> usage &= ~uWRITTEN ;
5227
+ if (wqptr - wqSIZE != wq )
5228
+ sym -> usage |= uNOLOOPVAR ;
5229
+ } /* if */
5230
+ } /* if */
5231
+ }
5232
+
5233
+ static void testloopvariables (symstate * loopvars ,int dowhile ,int line )
5234
+ {
5235
+ symbol * start ,* sym ;
5236
+ int num ,warnnum = 0 ;
5237
+
5238
+ /* the error messages are only printed on the "writing" pass,
5239
+ * so if we are not writing yet, then we have a quick exit */
5240
+ if (sc_status != statWRITE )
5241
+ return ;
5242
+
5243
+ /* skip labels */
5244
+ start = & loctab ;
5245
+ while ((start = start -> next )!= NULL && start -> ident == iLABEL )
5246
+ /* nothing */ ;
5247
+
5248
+ /* decrement pc_numloopvars by 1 for each variable that wasn't modified
5249
+ * inside the loop body; if pc_numloopvars gets zeroed after this, it would
5250
+ * mean none of the variables used inside the loop condition were modified */
5251
+ if (pc_numloopvars != 0 ) {
5252
+ warnnum = (pc_numloopvars == 1 ) ? 250 : 251 ;
5253
+ for (sym = start ; sym != NULL ; sym = sym -> next )
5254
+ if ((sym -> ident == iVARIABLE || sym -> ident == iREFERENCE )
5255
+ && (sym -> usage & (uLOOPVAR | uNOLOOPVAR ))== uLOOPVAR
5256
+ && (!dowhile || (sym -> usage & uWRITTEN )== 0 ))
5257
+ pc_numloopvars -- ;
5258
+ if (pc_numloopvars == 0 && warnnum == 251 ) {
5259
+ errorset (sSETPOS ,line );
5260
+ error (251 ); /* none of the variables used in loop condition are modified in loop body */
5261
+ errorset (sSETPOS ,-1 );
5262
+ } /* if */
5263
+ } /* if */
5264
+
5265
+ for (num = 0 ,sym = start ; sym != NULL ; num ++ ,sym = sym -> next ) {
5266
+ if (sym -> ident == iVARIABLE || sym -> ident == iREFERENCE ) {
5267
+ if ((sym -> usage & (uLOOPVAR | uNOLOOPVAR ))== uLOOPVAR ) {
5268
+ sym -> usage &= ~uLOOPVAR ;
5269
+ /* warn only if none of the variables used inside the loop condition
5270
+ * were modified inside the loop body */
5271
+ if (pc_numloopvars == 0 && warnnum == 250 ) {
5272
+ errorset (sSETPOS ,line );
5273
+ error (250 ,sym -> name ); /* variable used in loop condition not modified in loop body */
5274
+ errorset (sSETPOS ,-1 );
5275
+ } /* if */
5276
+ } /* if */
5277
+ sym -> usage &= ~uNOLOOPVAR ;
5278
+ if (loopvars != NULL )
5279
+ sym -> usage |= loopvars [num ].usage ;
5280
+ } /* if */
5281
+ } /* for */
5282
+ free (loopvars );
5283
+ }
5284
+
5176
5285
static cell calc_array_datasize (symbol * sym , cell * offset )
5177
5286
{
5178
5287
cell length ;
@@ -5883,7 +5992,7 @@ static int doif(void)
5883
5992
int ifindent ;
5884
5993
int lastst_true ;
5885
5994
int returnst = tIF ;
5886
- assigninfo * assignments = NULL ;
5995
+ symstate * assignments = NULL ;
5887
5996
5888
5997
lastst = 0 ; /* reset the last statement */
5889
5998
ifindent = stmtindent ; /* save the indent of the "if" instruction */
@@ -5924,28 +6033,37 @@ static int doif(void)
5924
6033
static int dowhile (void )
5925
6034
{
5926
6035
int wq [wqSIZE ]; /* allocate local queue */
5927
- int save_endlessloop ,retcode ;
6036
+ int save_endlessloop ,save_numloopvars ,retcode ;
6037
+ int loopline = fline ;
6038
+ symstate * loopvars = NULL ;
5928
6039
5929
6040
save_endlessloop = endlessloop ;
6041
+ save_numloopvars = pc_numloopvars ;
6042
+ pc_numloopvars = 0 ;
5930
6043
addwhile (wq ); /* add entry to queue for "break" */
5931
6044
setlabel (wq [wqLOOP ]); /* loop label */
5932
6045
/* The debugger uses the "break" opcode to be able to "break" out of
5933
6046
* a loop. To make sure that each loop has a break opcode, even for the
5934
6047
* tiniest loop, set it below the top of the loop
5935
6048
*/
5936
6049
setline (TRUE);
6050
+ scanloopvariables (& loopvars ,FALSE);
5937
6051
pc_nestlevel ++ ; /* temporarily increase the "compound statement" nesting level,
5938
6052
* so any assignments made inside the loop control expression
5939
6053
* could be cleaned up later */
6054
+ pc_loopcond = tWHILE ;
5940
6055
endlessloop = test (wq [wqEXIT ],TEST_DO ,FALSE);/* branch to wq[wqEXIT] if false */
6056
+ pc_loopcond = 0 ;
5941
6057
pc_nestlevel -- ;
5942
6058
statement (NULL ,FALSE); /* if so, do a statement */
5943
6059
clearassignments (pc_nestlevel + 1 );
6060
+ testloopvariables (loopvars ,FALSE,loopline );
5944
6061
jumplabel (wq [wqLOOP ]); /* and loop to "while" start */
5945
6062
setlabel (wq [wqEXIT ]); /* exit label */
5946
6063
delwhile (); /* delete queue entry */
5947
6064
5948
6065
retcode = endlessloop ? tENDLESS : tWHILE ;
6066
+ pc_numloopvars = save_numloopvars ;
5949
6067
endlessloop = save_endlessloop ;
5950
6068
return retcode ;
5951
6069
}
@@ -5957,28 +6075,37 @@ static int dowhile(void)
5957
6075
static int dodo (void )
5958
6076
{
5959
6077
int wq [wqSIZE ],top ;
5960
- int save_endlessloop ,retcode ;
6078
+ int save_endlessloop ,save_numloopvars ,retcode ;
6079
+ int loopline = fline ;
6080
+ symstate * loopvars = NULL ;
5961
6081
5962
6082
save_endlessloop = endlessloop ;
6083
+ save_numloopvars = pc_numloopvars ;
6084
+ pc_numloopvars = 0 ;
5963
6085
addwhile (wq ); /* see "dowhile" for more info */
5964
6086
top = getlabel (); /* make a label first */
5965
6087
setlabel (top ); /* loop label */
6088
+ scanloopvariables (& loopvars ,TRUE);
5966
6089
statement (NULL ,FALSE);
5967
6090
needtoken (tWHILE );
5968
6091
setlabel (wq [wqLOOP ]); /* "continue" always jumps to WQLOOP. */
5969
6092
setline (TRUE);
5970
6093
pc_nestlevel ++ ; /* temporarily increase the "compound statement" nesting level,
5971
6094
* so any assignments made inside the loop control expression
5972
6095
* could be cleaned up later */
6096
+ pc_loopcond = tDO ;
5973
6097
endlessloop = test (wq [wqEXIT ],TEST_OPT ,FALSE);
6098
+ pc_loopcond = 0 ;
5974
6099
pc_nestlevel -- ;
5975
6100
clearassignments (pc_nestlevel + 1 );
6101
+ testloopvariables (loopvars ,TRUE,loopline );
5976
6102
jumplabel (top );
5977
6103
setlabel (wq [wqEXIT ]);
5978
6104
delwhile ();
5979
6105
needtoken (tTERM );
5980
6106
5981
6107
retcode = endlessloop ? tENDLESS : tDO ;
6108
+ pc_numloopvars = save_numloopvars ;
5982
6109
endlessloop = save_endlessloop ;
5983
6110
return retcode ;
5984
6111
}
@@ -5987,13 +6114,17 @@ static int dofor(void)
5987
6114
{
5988
6115
int wq [wqSIZE ],skiplab ;
5989
6116
cell save_decl ;
5990
- int save_nestlevel ,save_endlessloop ;
6117
+ int save_nestlevel ,save_endlessloop , save_numloopvars ;
5991
6118
int index ,endtok ;
5992
6119
int * ptr ;
6120
+ int loopline = fline ;
6121
+ symstate * loopvars = NULL ;
5993
6122
5994
6123
save_decl = declared ;
5995
6124
save_nestlevel = pc_nestlevel ;
5996
6125
save_endlessloop = endlessloop ;
6126
+ save_numloopvars = pc_numloopvars ;
6127
+ pc_numloopvars = 0 ;
5997
6128
5998
6129
addwhile (wq );
5999
6130
skiplab = getlabel ();
@@ -6026,6 +6157,7 @@ static int dofor(void)
6026
6157
jumplabel (skiplab ); /* skip expression 3 1st time */
6027
6158
setlabel (wq [wqLOOP ]); /* "continue" goes to this label: expr3 */
6028
6159
setline (TRUE);
6160
+ scanloopvariables (& loopvars ,FALSE);
6029
6161
/* Expressions 2 and 3 are reversed in the generated code: expression 3
6030
6162
* precedes expression 2. When parsing, the code is buffered and marks for
6031
6163
* the start of each expression are insterted in the buffer.
@@ -6040,7 +6172,9 @@ static int dofor(void)
6040
6172
if (matchtoken (';' )) {
6041
6173
endlessloop = 1 ;
6042
6174
} else {
6175
+ pc_loopcond = tFOR ;
6043
6176
endlessloop = test (wq [wqEXIT ],TEST_PLAIN ,FALSE);/* expression 2 (jump to wq[wqEXIT] if false) */
6177
+ pc_loopcond = 0 ;
6044
6178
needtoken (';' );
6045
6179
} /* if */
6046
6180
stgmark ((char )(sEXPRSTART + 1 )); /* mark start of 3th expression in stage */
@@ -6053,6 +6187,7 @@ static int dofor(void)
6053
6187
stgset (FALSE); /* stop staging */
6054
6188
statement (NULL ,FALSE);
6055
6189
clearassignments (save_nestlevel + 1 );
6190
+ testloopvariables (loopvars ,FALSE,loopline );
6056
6191
jumplabel (wq [wqLOOP ]);
6057
6192
setlabel (wq [wqEXIT ]);
6058
6193
delwhile ();
@@ -6071,6 +6206,7 @@ static int dofor(void)
6071
6206
pc_nestlevel = save_nestlevel ; /* reset 'compound statement' nesting level */
6072
6207
6073
6208
index = endlessloop ? tENDLESS : tFOR ;
6209
+ pc_numloopvars = save_numloopvars ;
6074
6210
endlessloop = save_endlessloop ;
6075
6211
return index ;
6076
6212
}
@@ -6103,7 +6239,7 @@ static int doswitch(void)
6103
6239
constvalue_root caselist = { NULL , NULL }; /* case list starts empty */
6104
6240
constvalue * cse ,* csp ,* newval ;
6105
6241
char labelname [sNAMEMAX + 1 ];
6106
- assigninfo * assignments = NULL ;
6242
+ symstate * assignments = NULL ;
6107
6243
6108
6244
endtok = matchtoken ('(' ) ? ')' : tDO ;
6109
6245
ident = doexpr (TRUE,FALSE,FALSE,FALSE,& swtag ,NULL ,TRUE,NULL ); /* evaluate switch expression */
0 commit comments