Mon Apr 17 20:07:32 2023 UTC ()
lua: apply upstream bugfix for "'break' may not properly close variable in a 'for' loop."

Function 'leaveblock' was generating "break" label before removing
variables from the closing block. If 'createlabel' created a 'close'
instruction (which it did when matching a goto/break that exited
the scope of an upvalue), that instruction would use the wrong level.


(nikita)
diff -r1.13 -r1.14 src/external/mit/lua/dist/src/lparser.c

cvs diff -r1.13 -r1.14 src/external/mit/lua/dist/src/lparser.c (expand / switch to unified diff)

--- src/external/mit/lua/dist/src/lparser.c 2023/04/17 19:17:49 1.13
+++ src/external/mit/lua/dist/src/lparser.c 2023/04/17 20:07:32 1.14
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: lparser.c,v 1.13 2023/04/17 19:17:49 nikita Exp $ */ 1/* $NetBSD: lparser.c,v 1.14 2023/04/17 20:07:32 nikita Exp $ */
2 2
3/* 3/*
4** Id: lparser.c  4** Id: lparser.c
5** Lua Parser 5** Lua Parser
6** See Copyright Notice in lua.h 6** See Copyright Notice in lua.h
7*/ 7*/
8 8
9#define lparser_c 9#define lparser_c
10#define LUA_CORE 10#define LUA_CORE
11 11
12#include "lprefix.h" 12#include "lprefix.h"
13 13
14 14
@@ -668,39 +668,39 @@ static l_noret undefgoto (LexState *ls,  @@ -668,39 +668,39 @@ static l_noret undefgoto (LexState *ls,
668 else { 668 else {
669 msg = "no visible label '%s' for <goto> at line %d"; 669 msg = "no visible label '%s' for <goto> at line %d";
670 msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line); 670 msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line);
671 } 671 }
672 luaK_semerror(ls, msg); 672 luaK_semerror(ls, msg);
673} 673}
674 674
675 675
676static void leaveblock (FuncState *fs) { 676static void leaveblock (FuncState *fs) {
677 BlockCnt *bl = fs->bl; 677 BlockCnt *bl = fs->bl;
678 LexState *ls = fs->ls; 678 LexState *ls = fs->ls;
679 int hasclose = 0; 679 int hasclose = 0;
680 int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */ 680 int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */
681 if (bl->isloop) /* fix pending breaks? */ 681 removevars(fs, bl->nactvar); /* remove block locals */
 682 lua_assert(bl->nactvar == fs->nactvar); /* back to level on entry */
 683 if (bl->isloop) /* has to fix pending breaks? */
682 hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0); 684 hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0);
683 if (!hasclose && bl->previous && bl->upval) 685 if (!hasclose && bl->previous && bl->upval) /* still need a 'close'? */
684 luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0); 686 luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0);
685 fs->bl = bl->previous; 
686 removevars(fs, bl->nactvar); 
687 lua_assert(bl->nactvar == fs->nactvar); 
688 fs->freereg = stklevel; /* free registers */ 687 fs->freereg = stklevel; /* free registers */
689 ls->dyd->label.n = bl->firstlabel; /* remove local labels */ 688 ls->dyd->label.n = bl->firstlabel; /* remove local labels */
690 if (bl->previous) /* inner block? */ 689 fs->bl = bl->previous; /* current block now is previous one */
691 movegotosout(fs, bl); /* update pending gotos to outer block */ 690 if (bl->previous) /* was it a nested block? */
 691 movegotosout(fs, bl); /* update pending gotos to enclosing block */
692 else { 692 else {
693 if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ 693 if (bl->firstgoto < ls->dyd->gt.n) /* still pending gotos? */
694 undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ 694 undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */
695 } 695 }
696} 696}
697 697
698 698
699/* 699/*
700** adds a new prototype into list of prototypes 700** adds a new prototype into list of prototypes
701*/ 701*/
702static Proto *addprototype (LexState *ls) { 702static Proto *addprototype (LexState *ls) {
703 Proto *clp; 703 Proto *clp;
704 lua_State *L = ls->L; 704 lua_State *L = ls->L;
705 FuncState *fs = ls->fs; 705 FuncState *fs = ls->fs;
706 Proto *f = fs->f; /* prototype of current function */ 706 Proto *f = fs->f; /* prototype of current function */