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-github-47cffdc723c2e0c6dfaf62b7775ca1c1d338c0a4.tar.gz |
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) { /* +** Mark that current block has a to-be-closed variable. +*/ +static void marktobeclosed (FuncState *fs) { + BlockCnt *bl = fs->bl; + bl->upval = 1; + bl->insidetbc = 1; + fs->needclose = 1; +} + + +/* ** Find a variable with the given name 'n'. If it is an upvalue, add ** this upvalue into all intermediate functions. If it is a global, set ** 'var' as 'void' as a flag. @@ -1599,7 +1610,7 @@ static void forlist (LexState *ls, TString *indexname) { line = ls->linenumber; adjust_assign(ls, 4, explist(ls, &e), &e); adjustlocalvars(ls, 4); /* control variables */ - markupval(fs, fs->nactvar); /* last control var. must be closed */ + marktobeclosed(fs); /* last control var. must be closed */ luaK_checkstack(fs, 3); /* extra space to call generator */ forbody(ls, base, line, nvars - 4, 1); } @@ -1703,11 +1714,9 @@ static int getlocalattribute (LexState *ls) { } -static void checktoclose (LexState *ls, int level) { +static void checktoclose (FuncState *fs, int level) { if (level != -1) { /* is there a to-be-closed variable? */ - FuncState *fs = ls->fs; - markupval(fs, level + 1); - fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ + marktobeclosed(fs); luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0); } } @@ -1751,7 +1760,7 @@ static void localstat (LexState *ls) { adjust_assign(ls, nvars, nexps, &e); adjustlocalvars(ls, nvars); } - checktoclose(ls, toclose); + checktoclose(fs, toclose); } 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 end +do + -- bug in 5.4.3: previous condition (calls cannot be tail in the + -- scope of to-be-closed variables) must be valid for tbc variables + -- created by 'for' loops. + + local closed = false + + local function foo () + return function () return true end, 0, 0, + func2close(function () closed = true end) + end + + local function tail() return closed end + + local function foo1 () + for k in foo() do return tail() end + end + + assert(foo1() == false) + assert(closed == true) +end + + do print("testing errors in __close") -- original error is in __close |