diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-04-07 14:59:26 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-04-07 14:59:26 -0300 |
commit | 47cffdc723c2e0c6dfaf62b7775ca1c1d338c0a4 (patch) | |
tree | 54d46a0530aa2ee09db66d57c66bd313a5de530e | |
parent | 36de01d9885562444ae2e2a3e0b7e01b3fb8743b (diff) | |
download | lua-47cffdc723c2e0c6dfaf62b7775ca1c1d338c0a4.tar.gz lua-47cffdc723c2e0c6dfaf62b7775ca1c1d338c0a4.tar.bz2 lua-47cffdc723c2e0c6dfaf62b7775ca1c1d338c0a4.zip |
Bug: tbc variables in "for" loops don't avoid tail calls
-rw-r--r-- | lparser.c | 21 | ||||
-rw-r--r-- | testes/locals.lua | 23 |
2 files changed, 38 insertions, 6 deletions
@@ -417,6 +417,17 @@ static void markupval (FuncState *fs, int level) { | |||
417 | 417 | ||
418 | 418 | ||
419 | /* | 419 | /* |
420 | ** Mark that current block has a to-be-closed variable. | ||
421 | */ | ||
422 | static void marktobeclosed (FuncState *fs) { | ||
423 | BlockCnt *bl = fs->bl; | ||
424 | bl->upval = 1; | ||
425 | bl->insidetbc = 1; | ||
426 | fs->needclose = 1; | ||
427 | } | ||
428 | |||
429 | |||
430 | /* | ||
420 | ** Find a variable with the given name 'n'. If it is an upvalue, add | 431 | ** Find a variable with the given name 'n'. If it is an upvalue, add |
421 | ** this upvalue into all intermediate functions. If it is a global, set | 432 | ** this upvalue into all intermediate functions. If it is a global, set |
422 | ** 'var' as 'void' as a flag. | 433 | ** 'var' as 'void' as a flag. |
@@ -1599,7 +1610,7 @@ static void forlist (LexState *ls, TString *indexname) { | |||
1599 | line = ls->linenumber; | 1610 | line = ls->linenumber; |
1600 | adjust_assign(ls, 4, explist(ls, &e), &e); | 1611 | adjust_assign(ls, 4, explist(ls, &e), &e); |
1601 | adjustlocalvars(ls, 4); /* control variables */ | 1612 | adjustlocalvars(ls, 4); /* control variables */ |
1602 | markupval(fs, fs->nactvar); /* last control var. must be closed */ | 1613 | marktobeclosed(fs); /* last control var. must be closed */ |
1603 | luaK_checkstack(fs, 3); /* extra space to call generator */ | 1614 | luaK_checkstack(fs, 3); /* extra space to call generator */ |
1604 | forbody(ls, base, line, nvars - 4, 1); | 1615 | forbody(ls, base, line, nvars - 4, 1); |
1605 | } | 1616 | } |
@@ -1703,11 +1714,9 @@ static int getlocalattribute (LexState *ls) { | |||
1703 | } | 1714 | } |
1704 | 1715 | ||
1705 | 1716 | ||
1706 | static void checktoclose (LexState *ls, int level) { | 1717 | static void checktoclose (FuncState *fs, int level) { |
1707 | if (level != -1) { /* is there a to-be-closed variable? */ | 1718 | if (level != -1) { /* is there a to-be-closed variable? */ |
1708 | FuncState *fs = ls->fs; | 1719 | marktobeclosed(fs); |
1709 | markupval(fs, level + 1); | ||
1710 | fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ | ||
1711 | luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0); | 1720 | luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0); |
1712 | } | 1721 | } |
1713 | } | 1722 | } |
@@ -1751,7 +1760,7 @@ static void localstat (LexState *ls) { | |||
1751 | adjust_assign(ls, nvars, nexps, &e); | 1760 | adjust_assign(ls, nvars, nexps, &e); |
1752 | adjustlocalvars(ls, nvars); | 1761 | adjustlocalvars(ls, nvars); |
1753 | } | 1762 | } |
1754 | checktoclose(ls, toclose); | 1763 | checktoclose(fs, toclose); |
1755 | } | 1764 | } |
1756 | 1765 | ||
1757 | 1766 | ||
diff --git a/testes/locals.lua b/testes/locals.lua index 2c67edbd..6aad5d25 100644 --- a/testes/locals.lua +++ b/testes/locals.lua | |||
@@ -335,6 +335,29 @@ do | |||
335 | end | 335 | end |
336 | 336 | ||
337 | 337 | ||
338 | do | ||
339 | -- bug in 5.4.3: previous condition (calls cannot be tail in the | ||
340 | -- scope of to-be-closed variables) must be valid for tbc variables | ||
341 | -- created by 'for' loops. | ||
342 | |||
343 | local closed = false | ||
344 | |||
345 | local function foo () | ||
346 | return function () return true end, 0, 0, | ||
347 | func2close(function () closed = true end) | ||
348 | end | ||
349 | |||
350 | local function tail() return closed end | ||
351 | |||
352 | local function foo1 () | ||
353 | for k in foo() do return tail() end | ||
354 | end | ||
355 | |||
356 | assert(foo1() == false) | ||
357 | assert(closed == true) | ||
358 | end | ||
359 | |||
360 | |||
338 | do print("testing errors in __close") | 361 | do print("testing errors in __close") |
339 | 362 | ||
340 | -- original error is in __close | 363 | -- original error is in __close |