aboutsummaryrefslogtreecommitdiff
path: root/lparser.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2020-06-01 15:07:58 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2020-06-01 15:07:58 -0300
commit63295f1f7fa052fabcb4d69d49203cf33a7deef0 (patch)
tree05ba23f84fc76bd9a6b44883e7527ca1afcd274e /lparser.c
parent50523b107d5bcc8069b1aec4b5b11b3fcc87da8d (diff)
downloadlua-63295f1f7fa052fabcb4d69d49203cf33a7deef0.tar.gz
lua-63295f1f7fa052fabcb4d69d49203cf33a7deef0.tar.bz2
lua-63295f1f7fa052fabcb4d69d49203cf33a7deef0.zip
Fixed two bugs in to-be-closed variables x constants
The parser were mixing compiler indices of variables with stack indices, so that when a to-be-closed variable was used inside the scope of compile-time constants (which may be optimized away), it might be closed in the wrong place. (See new tests for examples.) Besides fixing the bugs, this commit also changed comments and variable names to avoid that kind of confusion and added tests.
Diffstat (limited to 'lparser.c')
-rw-r--r--lparser.c64
1 files changed, 36 insertions, 28 deletions
diff --git a/lparser.c b/lparser.c
index 27daa926..37102b72 100644
--- a/lparser.c
+++ b/lparser.c
@@ -212,27 +212,28 @@ static int new_localvar (LexState *ls, TString *name) {
212 212
213 213
214/* 214/*
215** Return the "variable description" (Vardesc) of a given 215** Return the "variable description" (Vardesc) of a given variable.
216** variable 216** (Unless noted otherwise, all variables are referred to by their
217** compiler indices.)
217*/ 218*/
218static Vardesc *getlocalvardesc (FuncState *fs, int i) { 219static Vardesc *getlocalvardesc (FuncState *fs, int vidx) {
219 return &fs->ls->dyd->actvar.arr[fs->firstlocal + i]; 220 return &fs->ls->dyd->actvar.arr[fs->firstlocal + vidx];
220} 221}
221 222
222 223
223/* 224/*
224** Convert 'nvar' (number of active variables at some point) to 225** Convert 'nvar', a compiler index level, to it corresponding
225** number of variables in the stack at that point. 226** stack index level. For that, search for the highest variable
227** below that level that is in the stack and uses its stack
228** index ('sidx').
226*/ 229*/
227static int stacklevel (FuncState *fs, int nvar) { 230static int stacklevel (FuncState *fs, int nvar) {
228 while (nvar > 0) { 231 while (nvar-- > 0) {
229 Vardesc *vd = getlocalvardesc(fs, nvar - 1); 232 Vardesc *vd = getlocalvardesc(fs, nvar); /* get variable */
230 if (vd->vd.kind != RDKCTC) /* is in the stack? */ 233 if (vd->vd.kind != RDKCTC) /* is in the stack? */
231 return vd->vd.sidx + 1; 234 return vd->vd.sidx + 1;
232 else
233 nvar--; /* try previous variable */
234 } 235 }
235 return 0; /* no variables */ 236 return 0; /* no variables in the stack */
236} 237}
237 238
238 239
@@ -245,10 +246,10 @@ int luaY_nvarstack (FuncState *fs) {
245 246
246 247
247/* 248/*
248** Get the debug-information entry for current variable 'i'. 249** Get the debug-information entry for current variable 'vidx'.
249*/ 250*/
250static LocVar *localdebuginfo (FuncState *fs, int i) { 251static LocVar *localdebuginfo (FuncState *fs, int vidx) {
251 Vardesc *vd = getlocalvardesc(fs, i); 252 Vardesc *vd = getlocalvardesc(fs, vidx);
252 if (vd->vd.kind == RDKCTC) 253 if (vd->vd.kind == RDKCTC)
253 return NULL; /* no debug info. for constants */ 254 return NULL; /* no debug info. for constants */
254 else { 255 else {
@@ -259,14 +260,20 @@ static LocVar *localdebuginfo (FuncState *fs, int i) {
259} 260}
260 261
261 262
262static void init_var (FuncState *fs, expdesc *e, int i) { 263/*
264** Create an expression representing variable 'vidx'
265*/
266static void init_var (FuncState *fs, expdesc *e, int vidx) {
263 e->f = e->t = NO_JUMP; 267 e->f = e->t = NO_JUMP;
264 e->k = VLOCAL; 268 e->k = VLOCAL;
265 e->u.var.vidx = i; 269 e->u.var.vidx = vidx;
266 e->u.var.sidx = getlocalvardesc(fs, i)->vd.sidx; 270 e->u.var.sidx = getlocalvardesc(fs, vidx)->vd.sidx;
267} 271}
268 272
269 273
274/*
275** Raises an error if variable described by 'e' is read only
276*/
270static void check_readonly (LexState *ls, expdesc *e) { 277static void check_readonly (LexState *ls, expdesc *e) {
271 FuncState *fs = ls->fs; 278 FuncState *fs = ls->fs;
272 TString *varname = NULL; /* to be set if variable is const */ 279 TString *varname = NULL; /* to be set if variable is const */
@@ -306,8 +313,8 @@ static void adjustlocalvars (LexState *ls, int nvars) {
306 int stklevel = luaY_nvarstack(fs); 313 int stklevel = luaY_nvarstack(fs);
307 int i; 314 int i;
308 for (i = 0; i < nvars; i++) { 315 for (i = 0; i < nvars; i++) {
309 int varidx = fs->nactvar++; 316 int vidx = fs->nactvar++;
310 Vardesc *var = getlocalvardesc(fs, varidx); 317 Vardesc *var = getlocalvardesc(fs, vidx);
311 var->vd.sidx = stklevel++; 318 var->vd.sidx = stklevel++;
312 var->vd.pidx = registerlocalvar(ls, fs, var->vd.name); 319 var->vd.pidx = registerlocalvar(ls, fs, var->vd.name);
313 } 320 }
@@ -377,7 +384,8 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
377 384
378/* 385/*
379** Look for an active local variable with the name 'n' in the 386** Look for an active local variable with the name 'n' in the
380** function 'fs'. 387** function 'fs'. If found, initialize 'var' with it and return
388** its expression kind; otherwise return -1.
381*/ 389*/
382static int searchvar (FuncState *fs, TString *n, expdesc *var) { 390static int searchvar (FuncState *fs, TString *n, expdesc *var) {
383 int i; 391 int i;
@@ -1592,7 +1600,7 @@ static void forlist (LexState *ls, TString *indexname) {
1592 line = ls->linenumber; 1600 line = ls->linenumber;
1593 adjust_assign(ls, 4, explist(ls, &e), &e); 1601 adjust_assign(ls, 4, explist(ls, &e), &e);
1594 adjustlocalvars(ls, 4); /* control variables */ 1602 adjustlocalvars(ls, 4); /* control variables */
1595 markupval(fs, luaY_nvarstack(fs)); /* state may create an upvalue */ 1603 markupval(fs, fs->nactvar); /* last control var. must be closed */
1596 luaK_checkstack(fs, 3); /* extra space to call generator */ 1604 luaK_checkstack(fs, 3); /* extra space to call generator */
1597 forbody(ls, base, line, nvars - 4, 1); 1605 forbody(ls, base, line, nvars - 4, 1);
1598} 1606}
@@ -1730,7 +1738,7 @@ static int getlocalattribute (LexState *ls) {
1730 luaK_semerror(ls, 1738 luaK_semerror(ls,
1731 luaO_pushfstring(ls->L, "unknown attribute '%s'", attr)); 1739 luaO_pushfstring(ls->L, "unknown attribute '%s'", attr));
1732 } 1740 }
1733 return VDKREG; 1741 return VDKREG; /* regular variable */
1734} 1742}
1735 1743
1736 1744
@@ -1739,7 +1747,7 @@ static void checktoclose (LexState *ls, int level) {
1739 FuncState *fs = ls->fs; 1747 FuncState *fs = ls->fs;
1740 markupval(fs, level + 1); 1748 markupval(fs, level + 1);
1741 fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ 1749 fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */
1742 luaK_codeABC(fs, OP_TBC, level, 0, 0); 1750 luaK_codeABC(fs, OP_TBC, stacklevel(fs, level), 0, 0);
1743 } 1751 }
1744} 1752}
1745 1753
@@ -1749,18 +1757,18 @@ static void localstat (LexState *ls) {
1749 FuncState *fs = ls->fs; 1757 FuncState *fs = ls->fs;
1750 int toclose = -1; /* index of to-be-closed variable (if any) */ 1758 int toclose = -1; /* index of to-be-closed variable (if any) */
1751 Vardesc *var; /* last variable */ 1759 Vardesc *var; /* last variable */
1752 int ivar, kind; /* index and kind of last variable */ 1760 int vidx, kind; /* index and kind of last variable */
1753 int nvars = 0; 1761 int nvars = 0;
1754 int nexps; 1762 int nexps;
1755 expdesc e; 1763 expdesc e;
1756 do { 1764 do {
1757 ivar = new_localvar(ls, str_checkname(ls)); 1765 vidx = new_localvar(ls, str_checkname(ls));
1758 kind = getlocalattribute(ls); 1766 kind = getlocalattribute(ls);
1759 getlocalvardesc(fs, ivar)->vd.kind = kind; 1767 getlocalvardesc(fs, vidx)->vd.kind = kind;
1760 if (kind == RDKTOCLOSE) { /* to-be-closed? */ 1768 if (kind == RDKTOCLOSE) { /* to-be-closed? */
1761 if (toclose != -1) /* one already present? */ 1769 if (toclose != -1) /* one already present? */
1762 luaK_semerror(ls, "multiple to-be-closed variables in local list"); 1770 luaK_semerror(ls, "multiple to-be-closed variables in local list");
1763 toclose = luaY_nvarstack(fs) + nvars; 1771 toclose = fs->nactvar + nvars;
1764 } 1772 }
1765 nvars++; 1773 nvars++;
1766 } while (testnext(ls, ',')); 1774 } while (testnext(ls, ','));
@@ -1770,7 +1778,7 @@ static void localstat (LexState *ls) {
1770 e.k = VVOID; 1778 e.k = VVOID;
1771 nexps = 0; 1779 nexps = 0;
1772 } 1780 }
1773 var = getlocalvardesc(fs, ivar); /* get last variable */ 1781 var = getlocalvardesc(fs, vidx); /* get last variable */
1774 if (nvars == nexps && /* no adjustments? */ 1782 if (nvars == nexps && /* no adjustments? */
1775 var->vd.kind == RDKCONST && /* last variable is const? */ 1783 var->vd.kind == RDKCONST && /* last variable is const? */
1776 luaK_exp2const(fs, &e, &var->k)) { /* compile-time constant? */ 1784 luaK_exp2const(fs, &e, &var->k)) { /* compile-time constant? */