@@ -116,6 +116,8 @@ static void make_report(symbol *root,FILE *log,char *sourcefile);
116116static void reduce_referrers (symbol * root );
117117static long max_stacksize (symbol * root ,int * recursion );
118118static 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 );
119121static void destructsymbols (symbol * root ,int level );
120122static constvalue * find_constval_byval (constvalue_root * table ,cell val );
121123static symbol * fetchlab (char * name );
@@ -919,6 +921,7 @@ static void resetglobals(void)
919921 pc_naked = FALSE;
920922 pc_retexpr = FALSE;
921923 pc_attributes = 0 ;
924+ pc_loopcond = 0 ;
922925 emit_flags = 0 ;
923926 emit_stgbuf_idx = -1 ;
924927}
@@ -5173,6 +5176,112 @@ static int testsymbols(symbol *root,int level,int testlabs,int testconst)
51735176 return entry ;
51745177}
51755178
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+
51765285static cell calc_array_datasize (symbol * sym , cell * offset )
51775286{
51785287 cell length ;
@@ -5883,7 +5992,7 @@ static int doif(void)
58835992 int ifindent ;
58845993 int lastst_true ;
58855994 int returnst = tIF ;
5886- assigninfo * assignments = NULL ;
5995+ symstate * assignments = NULL ;
58875996
58885997 lastst = 0 ; /* reset the last statement */
58895998 ifindent = stmtindent ; /* save the indent of the "if" instruction */
@@ -5924,28 +6033,37 @@ static int doif(void)
59246033static int dowhile (void )
59256034{
59266035 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 ;
59286039
59296040 save_endlessloop = endlessloop ;
6041+ save_numloopvars = pc_numloopvars ;
6042+ pc_numloopvars = 0 ;
59306043 addwhile (wq ); /* add entry to queue for "break" */
59316044 setlabel (wq [wqLOOP ]); /* loop label */
59326045 /* The debugger uses the "break" opcode to be able to "break" out of
59336046 * a loop. To make sure that each loop has a break opcode, even for the
59346047 * tiniest loop, set it below the top of the loop
59356048 */
59366049 setline (TRUE);
6050+ scanloopvariables (& loopvars ,FALSE);
59376051 pc_nestlevel ++ ; /* temporarily increase the "compound statement" nesting level,
59386052 * so any assignments made inside the loop control expression
59396053 * could be cleaned up later */
6054+ pc_loopcond = tWHILE ;
59406055 endlessloop = test (wq [wqEXIT ],TEST_DO ,FALSE);/* branch to wq[wqEXIT] if false */
6056+ pc_loopcond = 0 ;
59416057 pc_nestlevel -- ;
59426058 statement (NULL ,FALSE); /* if so, do a statement */
59436059 clearassignments (pc_nestlevel + 1 );
6060+ testloopvariables (loopvars ,FALSE,loopline );
59446061 jumplabel (wq [wqLOOP ]); /* and loop to "while" start */
59456062 setlabel (wq [wqEXIT ]); /* exit label */
59466063 delwhile (); /* delete queue entry */
59476064
59486065 retcode = endlessloop ? tENDLESS : tWHILE ;
6066+ pc_numloopvars = save_numloopvars ;
59496067 endlessloop = save_endlessloop ;
59506068 return retcode ;
59516069}
@@ -5957,28 +6075,37 @@ static int dowhile(void)
59576075static int dodo (void )
59586076{
59596077 int wq [wqSIZE ],top ;
5960- int save_endlessloop ,retcode ;
6078+ int save_endlessloop ,save_numloopvars ,retcode ;
6079+ int loopline = fline ;
6080+ symstate * loopvars = NULL ;
59616081
59626082 save_endlessloop = endlessloop ;
6083+ save_numloopvars = pc_numloopvars ;
6084+ pc_numloopvars = 0 ;
59636085 addwhile (wq ); /* see "dowhile" for more info */
59646086 top = getlabel (); /* make a label first */
59656087 setlabel (top ); /* loop label */
6088+ scanloopvariables (& loopvars ,TRUE);
59666089 statement (NULL ,FALSE);
59676090 needtoken (tWHILE );
59686091 setlabel (wq [wqLOOP ]); /* "continue" always jumps to WQLOOP. */
59696092 setline (TRUE);
59706093 pc_nestlevel ++ ; /* temporarily increase the "compound statement" nesting level,
59716094 * so any assignments made inside the loop control expression
59726095 * could be cleaned up later */
6096+ pc_loopcond = tDO ;
59736097 endlessloop = test (wq [wqEXIT ],TEST_OPT ,FALSE);
6098+ pc_loopcond = 0 ;
59746099 pc_nestlevel -- ;
59756100 clearassignments (pc_nestlevel + 1 );
6101+ testloopvariables (loopvars ,TRUE,loopline );
59766102 jumplabel (top );
59776103 setlabel (wq [wqEXIT ]);
59786104 delwhile ();
59796105 needtoken (tTERM );
59806106
59816107 retcode = endlessloop ? tENDLESS : tDO ;
6108+ pc_numloopvars = save_numloopvars ;
59826109 endlessloop = save_endlessloop ;
59836110 return retcode ;
59846111}
@@ -5987,13 +6114,17 @@ static int dofor(void)
59876114{
59886115 int wq [wqSIZE ],skiplab ;
59896116 cell save_decl ;
5990- int save_nestlevel ,save_endlessloop ;
6117+ int save_nestlevel ,save_endlessloop , save_numloopvars ;
59916118 int index ,endtok ;
59926119 int * ptr ;
6120+ int loopline = fline ;
6121+ symstate * loopvars = NULL ;
59936122
59946123 save_decl = declared ;
59956124 save_nestlevel = pc_nestlevel ;
59966125 save_endlessloop = endlessloop ;
6126+ save_numloopvars = pc_numloopvars ;
6127+ pc_numloopvars = 0 ;
59976128
59986129 addwhile (wq );
59996130 skiplab = getlabel ();
@@ -6026,6 +6157,7 @@ static int dofor(void)
60266157 jumplabel (skiplab ); /* skip expression 3 1st time */
60276158 setlabel (wq [wqLOOP ]); /* "continue" goes to this label: expr3 */
60286159 setline (TRUE);
6160+ scanloopvariables (& loopvars ,FALSE);
60296161 /* Expressions 2 and 3 are reversed in the generated code: expression 3
60306162 * precedes expression 2. When parsing, the code is buffered and marks for
60316163 * the start of each expression are insterted in the buffer.
@@ -6040,7 +6172,9 @@ static int dofor(void)
60406172 if (matchtoken (';' )) {
60416173 endlessloop = 1 ;
60426174 } else {
6175+ pc_loopcond = tFOR ;
60436176 endlessloop = test (wq [wqEXIT ],TEST_PLAIN ,FALSE);/* expression 2 (jump to wq[wqEXIT] if false) */
6177+ pc_loopcond = 0 ;
60446178 needtoken (';' );
60456179 } /* if */
60466180 stgmark ((char )(sEXPRSTART + 1 )); /* mark start of 3th expression in stage */
@@ -6053,6 +6187,7 @@ static int dofor(void)
60536187 stgset (FALSE); /* stop staging */
60546188 statement (NULL ,FALSE);
60556189 clearassignments (save_nestlevel + 1 );
6190+ testloopvariables (loopvars ,FALSE,loopline );
60566191 jumplabel (wq [wqLOOP ]);
60576192 setlabel (wq [wqEXIT ]);
60586193 delwhile ();
@@ -6071,6 +6206,7 @@ static int dofor(void)
60716206 pc_nestlevel = save_nestlevel ; /* reset 'compound statement' nesting level */
60726207
60736208 index = endlessloop ? tENDLESS : tFOR ;
6209+ pc_numloopvars = save_numloopvars ;
60746210 endlessloop = save_endlessloop ;
60756211 return index ;
60766212}
@@ -6103,7 +6239,7 @@ static int doswitch(void)
61036239 constvalue_root caselist = { NULL , NULL }; /* case list starts empty */
61046240 constvalue * cse ,* csp ,* newval ;
61056241 char labelname [sNAMEMAX + 1 ];
6106- assigninfo * assignments = NULL ;
6242+ symstate * assignments = NULL ;
61076243
61086244 endtok = matchtoken ('(' ) ? ')' : tDO ;
61096245 ident = doexpr (TRUE,FALSE,FALSE,FALSE,& swtag ,NULL ,TRUE,NULL ); /* evaluate switch expression */
0 commit comments