Lua diffu-lua-5.5.0-rc1-rc2


README

@@ -1,5 +1,5 @@
 
-This is Lua 5.5.0, released on 14 Nov 2025.
+This is Lua 5.5.0, released on 01 Dec 2025.
 
 For installation instructions, license details, and
 further information about Lua, see doc/readme.html.

doc/contents.html

@@ -85,7 +85,8 @@
 <LI><A HREF="manual.html#3.4.9">3.4.9 &ndash; Table Constructors</A>
 <LI><A HREF="manual.html#3.4.10">3.4.10 &ndash; Function Calls</A>
 <LI><A HREF="manual.html#3.4.11">3.4.11 &ndash; Function Definitions</A>
-<LI><A HREF="manual.html#3.4.12">3.4.12 &ndash; Lists of expressions, multiple results, and adjustment<A>
+<LI><A HREF="manual.html#3.4.12">3.4.12 &ndash; Lists of Expressions, Multiple Results, and Adjustment</A>
+</UL>
 </UL>
 <P>
 <LI><A HREF="manual.html#4">4 &ndash; The Application Program Interface</A>

@@ -94,7 +95,7 @@
 <UL>
 <LI><A HREF="manual.html#4.1.1">4.1.1 &ndash; Stack Size</A>
 <LI><A HREF="manual.html#4.1.2">4.1.2 &ndash; Valid and Acceptable Indices</A>
-<LI><A HREF="manual.html#4.1.3">4.1.3 &ndash; Pointers to strings</A>
+<LI><A HREF="manual.html#4.1.3">4.1.3 &ndash; Pointers to Strings</A>
 </UL>
 <LI><A HREF="manual.html#4.2">4.2 &ndash; C Closures</A>
 <LI><A HREF="manual.html#4.3">4.3 &ndash; Registry</A>

@@ -674,7 +675,7 @@
 
 <P CLASS="footer">
 Last update:
-Sat Nov 15 00:51:05 UTC 2025
+Mon Dec  1 13:57:23 UTC 2025
 </P>
 <!--
 Last change: revised for Lua 5.5.0

doc/manual.html

@@ -2701,7 +2701,7 @@
 </pre><p>
 can be used to emulate methods.
 A call <code>v:name(<em>args</em>)</code>
-is syntactic sugar for <code>v.name(v,<em>args</em>)</code>,
+is syntactic sugar for <code>v.name(v, <em>args</em>)</code>,
 except that <code>v</code> is evaluated only once.
 
 

@@ -2885,14 +2885,10 @@
 at the end of its parameter list.
 A variadic function does not adjust its argument list;
 instead, it collects all extra arguments and supplies them
-to the function through a <em>vararg expression</em> and,
-if present, a <em>vararg table</em>.
-
-
-<p>
-A vararg expression is also written as three dots,
-and its value is a list of all actual extra arguments,
-similar to a function with multiple results (see <a href="#3.4.12">&sect;3.4.12</a>).
+to the function through a <em>vararg table</em>.
+In that table,
+the values at indices 1, 2, etc. are the extra arguments,
+and the value at index "<code>n</code>" is the number of extra arguments.
 
 
 <p>

@@ -2904,7 +2900,7 @@
      function r() return 1,2,3 end
 </pre><p>
 Then, we have the following mapping from arguments to parameters and
-to the vararg expression:
+to the vararg table:
 
 <pre>
      CALL             PARAMETERS

@@ -2915,35 +2911,44 @@
      f(r(), 10)       a=1, b=10
      f(r())           a=1, b=2
      
-     g(3)             a=3, b=nil, ... -&gt;  (nothing)
-     g(3, 4)          a=3, b=4,   ... -&gt;  (nothing)
-     g(3, 4, 5, 8)    a=3, b=4,   ... -&gt;  5  8
-     g(5, r())        a=5, b=1,   ... -&gt;  2  3
+     g(3)             a=3, b=nil, va. table -&gt;  {n = 0}
+     g(3, 4)          a=3, b=4,   va. table -&gt;  {n = 0}
+     g(3, 4, 5, 8)    a=3, b=4,   va. table -&gt;  {5, 8, n = 2}
+     g(5, r())        a=5, b=1,   va. table -&gt;  {2, 3, n = 2}
 </pre>
 
 <p>
-The presence of a varag table in a variadic function is indicated
-by a name after the three dots.
+A vararg table in a variadic function can have an optional name,
+given after the three dots.
 When present,
-a vararg table behaves like a read-only local variable
-with the given name that is initialized with a table.
-In that table,
-the values at indices 1, 2, etc. are the extra arguments,
-and the value at index "<code>n</code>" is the number of extra arguments.
-In other words, the code behaves as if the function started with
-the following statement,
-assuming the standard behavior of <a href="#pdf-table.pack"><code>table.pack</code></a>:
+that name denotes a read-only local variable that
+refers to the vararg table.
+If the vararg table does not have a name,
+it can only be accessed through a vararg expression.
+
+
+<p>
+A vararg expression is also written as three dots,
+and its value is a list of the values in the vararg table,
+from 1 to the integer value at index "<code>n</code>".
+(Therefore, if the code does not modify the vararg table,
+this list corresponds to the extra arguments in the function call.)
+This list behaves like the results from a
+function with multiple results (see <a href="#3.4.12">&sect;3.4.12</a>).
 
-<pre>
-     local &lt;const&gt; name = table.pack(...)
-</pre>
 
 <p>
 As an optimization,
-if the vararg table is used only as a base in indexing expressions
-(the <code>t</code> in <code>t[exp]</code> or <code>t.id</code>) and it is not an upvalue,
+if the vararg table satisfies some conditions,
 the code does not create an actual table and instead translates
-the indexing expressions into accesses to the internal vararg data.
+the indexing expressions and the vararg expressions
+into accesses to the internal vararg data.
+The conditions are as follows:
+If the vararg table has a name,
+that name is not an upvalue in a nested function
+and it is used only as the base table
+in the syntactic constructions <code>t[exp]</code> or <code>t.id</code>).
+Note that an anonymous vararg table always satisfy these conditions.
 
 
 

@@ -2951,8 +2956,7 @@
 
 
 
-<h3>3.4.12 &ndash; <a name="3.4.12">Lists of expressions, multiple results,
-and adjustment</a></h3>
+<h3>3.4.12 &ndash; <a name="3.4.12">Lists of Expressions, Multiple Results, and Adjustment</a></h3>
 
 <p>
 Both function calls and vararg expressions can result in multiple values.

@@ -3256,7 +3260,7 @@
 
 
 
-<h3>4.1.3 &ndash; <a name="4.1.3">Pointers to strings</a></h3>
+<h3>4.1.3 &ndash; <a name="4.1.3">Pointers to Strings</a></h3>
 
 <p>
 Several functions in the API return pointers (<code>const char*</code>)

@@ -3751,7 +3755,7 @@
 </pre><p>
 Note that ISO&nbsp;C ensures
 that <code>free(NULL)</code> has no effect and that
-<code>realloc(NULL,size)</code> is equivalent to <code>malloc(size)</code>.
+<code>realloc(NULL, size)</code> is equivalent to <code>malloc(size)</code>.
 
 
 

@@ -5113,6 +5117,10 @@
 Lua will call <code>falloc</code> before raising the error.
 
 
+<p>
+The function returns a pointer to the string (that is, <code>s</code>).
+
+
 
 
 

@@ -10726,7 +10734,7 @@
 
 
 <p>
-<hr><h3><a name="pdf-math.ldexp"><code>math.ldexp(m, e)</code></a></h3>
+<hr><h3><a name="pdf-math.ldexp"><code>math.ldexp (m, e)</code></a></h3>
 
 
 <p>

@@ -11794,6 +11802,12 @@
 if they were optimized away by the compiler.
 Negative indices refer to vararg arguments;
 -1 is the first vararg argument.
+These negative indices are only available when the vararg table
+has been optimized away;
+otherwise, the vararg arguments are available in the vararg table.
+
+
+<p>
 The function returns <b>fail</b>
 if there is no variable with the given index,
 and raises an error when called with a level out of range.

@@ -12485,7 +12499,7 @@
 
 <P CLASS="footer">
 Last update:
-Sat Nov 15 00:41:28 UTC 2025
+Mon Dec  1 13:38:36 UTC 2025
 </P>
 <!--
 Last change: revised for Lua 5.5.0

src/lcode.c

@@ -806,7 +806,7 @@
 ** Change a vararg parameter into a regular local variable
 */
 void luaK_vapar2local (FuncState *fs, expdesc *var) {
-  fs->f->flag |= PF_VATAB;  /* function will need a vararg table */
+  needvatab(fs->f);  /* function will need a vararg table */
   /* now a vararg parameter is equivalent to a regular local variable */
   var->k = VLOCAL;
 }

@@ -1127,7 +1127,7 @@
       break;
     }
     case VVARGIND: {
-      fs->f->flag |= PF_VATAB;  /* function will need a vararg table */
+      needvatab(fs->f);  /* function will need a vararg table */
       /* now, assignment is to a regular table */
     }  /* FALLTHROUGH */
     case VINDEXED: {

@@ -1927,6 +1927,8 @@
 void luaK_finish (FuncState *fs) {
   int i;
   Proto *p = fs->f;
+  if (p->flag & PF_VATAB)  /* will it use a vararg table? */
+    p->flag &= cast_byte(~PF_VAHID);  /* then it will not use hidden args. */
   for (i = 0; i < fs->pc; i++) {
     Instruction *pc = &p->code[i];
     /* avoid "not used" warnings when assert is off (for 'onelua.c') */

@@ -1934,7 +1936,7 @@
     lua_assert(i == 0 || luaP_isOT(*(pc - 1)) == luaP_isIT(*pc));
     switch (GET_OPCODE(*pc)) {
       case OP_RETURN0: case OP_RETURN1: {
-        if (!(fs->needclose || (p->flag & PF_ISVARARG)))
+        if (!(fs->needclose || (p->flag & PF_VAHID)))
           break;  /* no extra work */
         /* else use OP_RETURN to do the extra work */
         SET_OPCODE(*pc, OP_RETURN);

@@ -1942,8 +1944,8 @@
       case OP_RETURN: case OP_TAILCALL: {
         if (fs->needclose)
           SETARG_k(*pc, 1);  /* signal that it needs to close */
-        if (p->flag & PF_ISVARARG)
-          SETARG_C(*pc, p->numparams + 1);  /* signal that it is vararg */
+        if (p->flag & PF_VAHID)  /* does it use hidden arguments? */
+          SETARG_C(*pc, p->numparams + 1);  /* signal that */
         break;
       }
       case OP_GETVARG: {

@@ -1951,6 +1953,11 @@
           SET_OPCODE(*pc, OP_GETTABLE);  /* must get vararg there */
         break;
       }
+      case OP_VARARG: {
+        if (p->flag & PF_VATAB)  /* function has a vararg table? */
+          SETARG_k(*pc, 1);  /* must get vararg there */
+        break;
+      }
       case OP_JMP: {  /* to optimize jumps to jumps */
         int target = finaltarget(p->code, i);
         fixjump(fs, i, target);  /* jump directly to final target */

src/lcorolib.c

@@ -189,15 +189,17 @@
         return 2;
       }
     }
-    case COS_RUN:  /* running coroutine? */
+    case COS_NORM:
+      return luaL_error(L, "cannot close a %s coroutine", statname[status]);
+    case COS_RUN:
       lua_geti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD);  /* get main */
       if (lua_tothread(L, -1) == co)
         return luaL_error(L, "cannot close main thread");
       lua_closethread(co, L);  /* close itself */
-      lua_assert(0);  /* previous call does not return */
+      /* previous call does not return *//* FALLTHROUGH */
+    default:
+      lua_assert(0);
       return 0;
-    default:  /* normal or running coroutine */
-      return luaL_error(L, "cannot close a %s coroutine", statname[status]);
   }
 }
 

src/ldebug.c

@@ -184,7 +184,7 @@
 
 
 static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
-  if (clLvalue(s2v(ci->func.p))->p->flag & PF_ISVARARG) {
+  if (clLvalue(s2v(ci->func.p))->p->flag & PF_VAHID) {
     int nextra = ci->u.l.nextraargs;
     if (n >= -nextra) {  /* 'n' is negative */
       *pos = ci->func.p - nextra - (n + 1);

@@ -304,7 +304,7 @@
       int i;
       TValue v;
       setbtvalue(&v);  /* boolean 'true' to be the value of all indices */
-      if (!(p->flag & PF_ISVARARG))  /* regular function? */
+      if (!(isvararg(p)))  /* regular function? */
         i = 0;  /* consider all instructions */
       else {  /* vararg function */
         lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP);

@@ -348,7 +348,7 @@
           ar->nparams = 0;
         }
         else {
-          ar->isvararg = (f->l.p->flag & PF_ISVARARG) ? 1 : 0;
+          ar->isvararg = (isvararg(f->l.p)) ? 1 : 0;
           ar->nparams = f->l.p->numparams;
         }
         break;

@@ -912,7 +912,7 @@
   Proto *p = ci_func(ci)->p;
   ci->u.l.trap = 1;  /* ensure hooks will be checked */
   if (ci->u.l.savedpc == p->code) {  /* first instruction (not resuming)? */
-    if (p->flag & PF_ISVARARG)
+    if (isvararg(p))
       return 0;  /* hooks will start at VARARGPREP instruction */
     else if (!(ci->callstatus & CIST_HOOKYIELD))  /* not yielded? */
       luaD_hookcall(L, ci);  /* check 'call' hook */

src/ldo.c

@@ -487,7 +487,7 @@
     int ftransfer;
     if (isLua(ci)) {
       Proto *p = ci_func(ci)->p;
-      if (p->flag & PF_ISVARARG)
+      if (p->flag & PF_VAHID)
         delta = ci->u.l.nextraargs + p->numparams + 1;
     }
     ci->func.p += delta;  /* if vararg, back to virtual 'func' */

src/lobject.h

@@ -583,11 +583,18 @@
 /*
 ** Flags in Prototypes
 */
-#define PF_ISVARARG	1  /* function is vararg */
-#define PF_VAVAR	2  /* function has vararg parameter */
-#define PF_VATAB	4  /* function has vararg table */
-#define PF_FIXED	8  /* prototype has parts in fixed memory */
+#define PF_VAHID	1  /* function has hidden vararg arguments */
+#define PF_VATAB	2  /* function has vararg table */
+#define PF_FIXED	4  /* prototype has parts in fixed memory */
 
+/* a vararg function either has hidden args. or a vararg table */
+#define isvararg(p)	((p)->flag & (PF_VAHID | PF_VATAB))
+
+/*
+** mark that a function needs a vararg table. (The flag PF_VAHID will
+** be cleared later.)
+*/
+#define needvatab(p)	((p)->flag |= PF_VATAB)
 
 /*
 ** Function Prototypes

src/lopcodes.h

@@ -224,8 +224,8 @@
 
 
 /*
-** Grep "ORDER OP" if you change these enums. Opcodes marked with a (*)
-** has extra descriptions in the notes after the enumeration.
+** Grep "ORDER OP" if you change this enum.
+** See "Notes" below for more information about some instructions.
 */
 
 typedef enum {

@@ -238,7 +238,7 @@
 OP_LOADK,/*	A Bx	R[A] := K[Bx]					*/
 OP_LOADKX,/*	A	R[A] := K[extra arg]				*/
 OP_LOADFALSE,/*	A	R[A] := false					*/
-OP_LFALSESKIP,/*A	R[A] := false; pc++	(*)			*/
+OP_LFALSESKIP,/*A	R[A] := false; pc++				*/
 OP_LOADTRUE,/*	A	R[A] := true					*/
 OP_LOADNIL,/*	A B	R[A], R[A+1], ..., R[A+B] := nil		*/
 OP_GETUPVAL,/*	A B	R[A] := UpValue[B]				*/

@@ -289,7 +289,7 @@
 OP_SHL,/*	A B C	R[A] := R[B] << R[C]				*/
 OP_SHR,/*	A B C	R[A] := R[B] >> R[C]				*/
 
-OP_MMBIN,/*	A B C	call C metamethod over R[A] and R[B]	(*)	*/
+OP_MMBIN,/*	A B C	call C metamethod over R[A] and R[B]		*/
 OP_MMBINI,/*	A sB C k	call C metamethod over R[A] and sB	*/
 OP_MMBINK,/*	A B C k		call C metamethod over R[A] and K[B]	*/
 

@@ -315,12 +315,12 @@
 OP_GEI,/*	A sB k	if ((R[A] >= sB) ~= k) then pc++		*/
 
 OP_TEST,/*	A k	if (not R[A] == k) then pc++			*/
-OP_TESTSET,/*	A B k	if (not R[B] == k) then pc++ else R[A] := R[B] (*) */
+OP_TESTSET,/*	A B k	if (not R[B] == k) then pc++ else R[A] := R[B]  */
 
 OP_CALL,/*	A B C	R[A], ... ,R[A+C-2] := R[A](R[A+1], ... ,R[A+B-1]) */
 OP_TAILCALL,/*	A B C k	return R[A](R[A+1], ... ,R[A+B-1])		*/
 
-OP_RETURN,/*	A B C k	return R[A], ... ,R[A+B-2]	(see note)	*/
+OP_RETURN,/*	A B C k	return R[A], ... ,R[A+B-2]			*/
 OP_RETURN0,/*		return						*/
 OP_RETURN1,/*	A	return R[A]					*/
 

@@ -336,13 +336,13 @@
 
 OP_CLOSURE,/*	A Bx	R[A] := closure(KPROTO[Bx])			*/
 
-OP_VARARG,/*	A C	R[A], R[A+1], ..., R[A+C-2] = vararg		*/
+OP_VARARG,/*	A B C k	R[A], ..., R[A+C-2] = varargs  			*/
 
 OP_GETVARG, /* A B C	R[A] := R[B][R[C]], R[B] is vararg parameter    */
 
-OP_ERRNNIL,/*	A Bx	raise error if R[A] ~= nil (K[Bx] is global name)*/
+OP_ERRNNIL,/*	A Bx	raise error if R[A] ~= nil (K[Bx - 1] is global name)*/
 
-OP_VARARGPREP,/* 	(adjust vararg parameters)			*/
+OP_VARARGPREP,/* 	(adjust varargs)				*/
 
 OP_EXTRAARG/*	Ax	extra (larger) argument for previous opcode	*/
 } OpCode;

@@ -371,7 +371,8 @@
   OP_RETURN*, OP_SETLIST) may use 'top'.
 
   (*) In OP_VARARG, if (C == 0) then use actual number of varargs and
-  set top (like in OP_CALL with C == 0).
+  set top (like in OP_CALL with C == 0). 'k' means function has a
+  vararg table, which is in R[B].
 
   (*) In OP_RETURN, if (B == 0) then return up to 'top'.
 

@@ -386,18 +387,23 @@
   power of 2) plus 1, or zero for size zero. If not k, the array size
   is vC. Otherwise, the array size is EXTRAARG _ vC.
 
+  (*) In OP_ERRNNIL, (Bx == 0) means index of global name doesn't
+  fit in Bx. (So, that name is not available for the error message.)
+
   (*) For comparisons, k specifies what condition the test should accept
   (true or false).
 
   (*) In OP_MMBINI/OP_MMBINK, k means the arguments were flipped
-   (the constant is the first operand).
+  (the constant is the first operand).
 
-  (*) All 'skips' (pc++) assume that next instruction is a jump.
+  (*) All comparison and test instructions assume that the instruction
+  being skipped (pc++) is a jump.
 
   (*) In instructions OP_RETURN/OP_TAILCALL, 'k' specifies that the
   function builds upvalues, which may need to be closed. C > 0 means
-  the function is vararg, so that its 'func' must be corrected before
-  returning; in this case, (C - 1) is its number of fixed parameters.
+  the function has hidden vararg arguments, so that its 'func' must be
+  corrected before returning; in this case, (C - 1) is its number of
+  fixed parameters.
 
   (*) In comparisons with an immediate operand, C signals whether the
   original operand was a float. (It must be corrected in case of

src/lparser.c

@@ -304,7 +304,7 @@
       break;
     }
     case VVARGIND: {
-      fs->f->flag |= PF_VATAB;  /* function will need a vararg table */
+      needvatab(fs->f);  /* function will need a vararg table */
       e->k = VINDEXED;
     }  /* FALLTHROUGH */
     case VINDEXUP: case VINDEXSTR: case VINDEXED: {  /* global variable */

@@ -1056,9 +1056,8 @@
 /* }====================================================================== */
 
 
-static void setvararg (FuncState *fs, int kind) {
-  lua_assert(kind & PF_ISVARARG);
-  fs->f->flag |= cast_byte(kind);
+static void setvararg (FuncState *fs) {
+  fs->f->flag |= PF_VAHID;  /* by default, use hidden vararg arguments */
   luaK_codeABC(fs, OP_VARARGPREP, 0, 0, 0);
 }
 

@@ -1078,12 +1077,12 @@
           break;
         }
         case TK_DOTS: {
-          varargk |= PF_ISVARARG;
+          varargk = 1;
           luaX_next(ls);  /* skip '...' */
-          if (ls->t.token == TK_NAME) {
+          if (ls->t.token == TK_NAME)
             new_varkind(ls, str_checkname(ls), RDKVAVAR);
-            varargk |= PF_VAVAR;
-          }
+          else
+            new_localvarliteral(ls, "(vararg table)");
           break;
         }
         default: luaX_syntaxerror(ls, "<name> or '...' expected");

@@ -1092,10 +1091,9 @@
   }
   adjustlocalvars(ls, nparams);
   f->numparams = cast_byte(fs->nactvar);
-  if (varargk != 0) {
-    setvararg(fs, varargk);  /* declared vararg */
-    if (varargk & PF_VAVAR)
-      adjustlocalvars(ls, 1);  /* vararg parameter */
+  if (varargk) {
+    setvararg(fs);  /* declared vararg */
+    adjustlocalvars(ls, 1);  /* vararg parameter */
   }
   /* reserve registers for parameters (plus vararg parameter, if present) */
   luaK_reserveregs(fs, fs->nactvar);

@@ -1285,9 +1283,9 @@
     }
     case TK_DOTS: {  /* vararg */
       FuncState *fs = ls->fs;
-      check_condition(ls, fs->f->flag & PF_ISVARARG,
+      check_condition(ls, isvararg(fs->f),
                       "cannot use '...' outside a vararg function");
-      init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 0, 1));
+      init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, fs->f->numparams, 1));
       break;
     }
     case '{' /*}*/: {  /* constructor */

@@ -2153,7 +2151,7 @@
   BlockCnt bl;
   Upvaldesc *env;
   open_func(ls, fs, &bl);
-  setvararg(fs, PF_ISVARARG);  /* main function is always vararg */
+  setvararg(fs);  /* main function is always vararg */
   env = allocupvalue(fs);  /* ...set environment upvalue */
   env->instack = 1;
   env->idx = 0;

src/ltm.c

@@ -242,6 +242,7 @@
   luaH_set(L, t, &key, &value);  /* t.n = n */
   for (i = 0; i < n; i++)
     luaH_setint(L, t, i + 1, s2v(f + i));
+  luaC_checkGC(L);
 }
 
 

@@ -249,31 +250,42 @@
 ** initial stack:  func arg1 ... argn extra1 ...
 **                 ^ ci->func                    ^ L->top
 ** final stack: func nil ... nil extra1 ... func arg1 ... argn
-**                                          ^ ci->func         ^ L->top
+**                                          ^ ci->func
 */
-void luaT_adjustvarargs (lua_State *L, CallInfo *ci, const Proto *p) {
+static void buildhiddenargs (lua_State *L, CallInfo *ci, const Proto *p,
+                             int totalargs, int nfixparams, int nextra) {
   int i;
-  int totalargs = cast_int(L->top.p - ci->func.p) - 1;
-  int nfixparams = p->numparams;
-  int nextra = totalargs - nfixparams;  /* number of extra arguments */
   ci->u.l.nextraargs = nextra;
   luaD_checkstack(L, p->maxstacksize + 1);
-  /* copy function to the top of the stack */
+  /* copy function to the top of the stack, after extra arguments */
   setobjs2s(L, L->top.p++, ci->func.p);
-  /* move fixed parameters to the top of the stack */
+  /* move fixed parameters to after the copied function */
   for (i = 1; i <= nfixparams; i++) {
     setobjs2s(L, L->top.p++, ci->func.p + i);
     setnilvalue(s2v(ci->func.p + i));  /* erase original parameter (for GC) */
   }
-  if (p->flag & PF_VAVAR) {  /* is there a vararg parameter? */
-    if (p->flag & PF_VATAB)  /* does it need a vararg table? */
-      createvarargtab(L, ci->func.p + nfixparams + 1, nextra);
-    else  /* no table; set parameter to nil */
-      setnilvalue(s2v(L->top.p));
-  }
-  ci->func.p += totalargs + 1;
+  ci->func.p += totalargs + 1;  /* 'func' now lives after hidden arguments */
   ci->top.p += totalargs + 1;
-  lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
+}
+
+
+void luaT_adjustvarargs (lua_State *L, CallInfo *ci, const Proto *p) {
+  int totalargs = cast_int(L->top.p - ci->func.p) - 1;
+  int nfixparams = p->numparams;
+  int nextra = totalargs - nfixparams;  /* number of extra arguments */
+  if (p->flag & PF_VATAB) {  /* does it need a vararg table? */
+    lua_assert(!(p->flag & PF_VAHID));
+    createvarargtab(L, ci->func.p + nfixparams + 1, nextra);
+    /* move table to proper place (last parameter) */
+    setobjs2s(L, ci->func.p + nfixparams + 1, L->top.p - 1);
+  }
+  else {  /* no table */
+    lua_assert(p->flag & PF_VAHID);
+    buildhiddenargs(L, ci, p, totalargs, nfixparams, nextra);
+    /* set vararg parameter to nil */
+    setnilvalue(s2v(ci->func.p + nfixparams + 1));
+    lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
+  }
 }
 
 

@@ -299,16 +311,53 @@
 }
 
 
-void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
-  int i;
-  int nextra = ci->u.l.nextraargs;
+/*
+** Get the number of extra arguments in a vararg function. If vararg
+** table has been optimized away, that number is in the call info.
+** Otherwise, get the field 'n' from the vararg table and check that it
+** has a proper value (non-negative integer not larger than the stack
+** limit).
+*/
+static int getnumargs (lua_State *L, CallInfo *ci, Table *h) {
+  if (h == NULL)  /* no vararg table? */
+    return ci->u.l.nextraargs;
+  else {
+    TValue res;
+    if (luaH_getshortstr(h, luaS_new(L, "n"), &res) != LUA_VNUMINT ||
+        l_castS2U(ivalue(&res)) > cast_uint(INT_MAX/2))
+      luaG_runerror(L, "vararg table has no proper 'n'");
+    return cast_int(ivalue(&res));
+  }
+}
+
+
+/*
+** Get 'wanted' vararg arguments and put them in 'where'. 'vatab' is
+** the register of the vararg table or -1 if there is no vararg table.
+*/
+void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted,
+                                    int vatab) {
+  Table *h = (vatab < 0) ? NULL : hvalue(s2v(ci->func.p + vatab + 1));
+  int nargs = getnumargs(L, ci, h);  /* number of available vararg args. */
+  int i, touse;  /* 'touse' is minimum between 'wanted' and 'nargs' */
   if (wanted < 0) {
-    wanted = nextra;  /* get all extra arguments available */
-    checkstackp(L, nextra, where);  /* ensure stack space */
-    L->top.p = where + nextra;  /* next instruction will need top */
+    touse = wanted = nargs;  /* get all extra arguments available */
+    checkstackp(L, nargs, where);  /* ensure stack space */
+    L->top.p = where + nargs;  /* next instruction will need top */
+  }
+  else
+    touse = (nargs > wanted) ? wanted : nargs;
+  if (h == NULL) {  /* no vararg table? */
+    for (i = 0; i < touse; i++)  /* get vararg values from the stack */
+      setobjs2s(L, where + i, ci->func.p - nargs + i);
+  }
+  else {  /* get vararg values from vararg table */
+    for (i = 0; i < touse; i++) {
+      lu_byte tag = luaH_getint(h, i + 1, s2v(where + i));
+      if (tagisempty(tag))
+       setnilvalue(s2v(where + i));
+    }
   }
-  for (i = 0; i < wanted && i < nextra; i++)
-    setobjs2s(L, where + i, ci->func.p - nextra + i);
   for (; i < wanted; i++)   /* complete required results with nil */
     setnilvalue(s2v(where + i));
 }

src/ltm.h

@@ -98,8 +98,8 @@
 LUAI_FUNC void luaT_adjustvarargs (lua_State *L, struct CallInfo *ci,
                                                  const Proto *p);
 LUAI_FUNC void luaT_getvararg (CallInfo *ci, StkId ra, TValue *rc);
-LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
-                                              StkId where, int wanted);
+LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci, StkId where,
+                                              int wanted, int vatab);
 
 
 #endif

src/luac.c

@@ -347,6 +347,8 @@
   int bx=GETARG_Bx(i);
   int sb=GETARG_sB(i);
   int sc=GETARG_sC(i);
+  int vb=GETARG_vB(i);
+  int vc=GETARG_vC(i);
   int sbx=GETARG_sBx(i);
   int isk=GETARG_k(i);
   int line=luaG_getfuncline(f,pc);

@@ -428,8 +430,8 @@
 	if (isk) { printf(" "); PrintConstant(f,c); }
 	break;
    case OP_NEWTABLE:
-	printf("%d %d %d",a,b,c);
-	printf(COMMENT "%d",c+EXTRAARGC);
+	printf("%d %d %d%s",a,vb,vc,ISK);
+	printf(COMMENT "%d",vc+EXTRAARGC);
 	break;
    case OP_SELF:
 	printf("%d %d %d%s",a,b,c,ISK);

@@ -633,7 +635,7 @@
 	printf(COMMENT "to %d",pc-bx+2);
 	break;
    case OP_SETLIST:
-	printf("%d %d %d",a,b,c);
+	printf("%d %d %d%s",a,vb,vc,ISK);
 	if (isk) printf(COMMENT "%d",c+EXTRAARGC);
 	break;
    case OP_CLOSURE:

@@ -641,7 +643,7 @@
 	printf(COMMENT "%p",VOID(f->p[bx]));
 	break;
    case OP_VARARG:
-	printf("%d %d",a,c);
+	printf("%d %d %d%s",a,b,c,ISK);
 	printf(COMMENT);
 	if (c==0) printf("all out"); else printf("%d out",c-1);
 	break;

@@ -650,7 +652,8 @@
 	break;
    case OP_ERRNNIL:
 	printf("%d %d",a,bx);
-	printf(COMMENT); PrintConstant(f,bx);
+	printf(COMMENT);
+	if (bx==0) printf("?"); else PrintConstant(f,bx-1);
 	break;
    case OP_VARARGPREP:
 	printf("%d",a);

@@ -686,7 +689,7 @@
 	f->linedefined,f->lastlinedefined,
 	S(f->sizecode),VOID(f));
  printf("%d%s param%s, %d slot%s, %d upvalue%s, ",
-	(int)(f->numparams),(f->flag & PF_ISVARARG)?"+":"",SS(f->numparams),
+	(int)(f->numparams),isvararg(f)?"+":"",SS(f->numparams),
 	S(f->maxstacksize),S(f->sizeupvalues));
  printf("%d local%s, %d constant%s, %d function%s\n",
 	S(f->sizelocvars),S(f->sizek),S(f->sizep));

src/lvm.c

@@ -1935,8 +1935,9 @@
       }
       vmcase(OP_VARARG) {
         StkId ra = RA(i);
-        int n = GETARG_C(i) - 1;  /* required results */
-        Protect(luaT_getvarargs(L, ci, ra, n));
+        int n = GETARG_C(i) - 1;  /* required results (-1 means all) */
+        int vatab = GETARG_k(i) ? GETARG_B(i) : -1;
+        Protect(luaT_getvarargs(L, ci, ra, n, vatab));
         vmbreak;
       }
       vmcase(OP_GETVARG) {