Details

- After converting a generic GCObject to a specific type ('gco2*'),
  avoid using the original GCObject (to reduce aliasing).
- Small corrections in comments in 'lopcodes.h'
- Added tests about who calls __close metamethods
diff --git a/lfunc.c b/lfunc.c
index 88d4532..c4360f0 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -53,7 +53,7 @@
     uv->v = &uv->u.value;  /* make it closed */
     setnilvalue(uv->v);
     cl->upvals[i] = uv;
-    luaC_objbarrier(L, cl, o);
+    luaC_objbarrier(L, cl, uv);
   }
 }
 
diff --git a/lgc.c b/lgc.c
index 3b8d0ed..03326df 100644
--- a/lgc.c
+++ b/lgc.c
@@ -301,7 +301,7 @@
       if (upisopen(uv))
         set2gray(uv);  /* open upvalues are kept gray */
       else
-        set2black(o);  /* closed upvalues are visited here */
+        set2black(uv);  /* closed upvalues are visited here */
       markvalue(g, uv->v);  /* mark its content */
       break;
     }
@@ -309,7 +309,7 @@
       Udata *u = gco2u(o);
       if (u->nuvalue == 0) {  /* no user values? */
         markobjectN(g, u->metatable);  /* mark its metatable */
-        set2black(o);  /* nothing else to mark */
+        set2black(u);  /* nothing else to mark */
         break;
       }
       /* else... */
@@ -770,12 +770,16 @@
     case LUA_VUPVAL:
       freeupval(L, gco2upv(o));
       break;
-    case LUA_VLCL:
-      luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues));
+    case LUA_VLCL: {
+      LClosure *cl = gco2lcl(o);
+      luaM_freemem(L, cl, sizeLclosure(cl->nupvalues));
       break;
-    case LUA_VCCL:
-      luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues));
+    }
+    case LUA_VCCL: {
+      CClosure *cl = gco2ccl(o);
+      luaM_freemem(L, cl, sizeCclosure(cl->nupvalues));
       break;
+    }
     case LUA_VTABLE:
       luaH_free(L, gco2t(o));
       break;
@@ -787,13 +791,17 @@
       luaM_freemem(L, o, sizeudata(u->nuvalue, u->len));
       break;
     }
-    case LUA_VSHRSTR:
-      luaS_remove(L, gco2ts(o));  /* remove it from hash table */
-      luaM_freemem(L, o, sizelstring(gco2ts(o)->shrlen));
+    case LUA_VSHRSTR: {
+      TString *ts = gco2ts(o);
+      luaS_remove(L, ts);  /* remove it from hash table */
+      luaM_freemem(L, ts, sizelstring(ts->shrlen));
       break;
-    case LUA_VLNGSTR:
-      luaM_freemem(L, o, sizelstring(gco2ts(o)->u.lnglen));
+    }
+    case LUA_VLNGSTR: {
+      TString *ts = gco2ts(o);
+      luaM_freemem(L, ts, sizelstring(ts->u.lnglen));
       break;
+    }
     default: lua_assert(0);
   }
 }
diff --git a/lopcodes.h b/lopcodes.h
index 122e5d2..120cdd9 100644
--- a/lopcodes.h
+++ b/lopcodes.h
@@ -261,7 +261,7 @@
 OP_UNM,/*	A B	R[A] := -R[B]					*/
 OP_BNOT,/*	A B	R[A] := ~R[B]					*/
 OP_NOT,/*	A B	R[A] := not R[B]				*/
-OP_LEN,/*	A B	R[A] := length of R[B]				*/
+OP_LEN,/*	A B	R[A] := #R[B] (length operator)			*/
 
 OP_CONCAT,/*	A B	R[A] := R[A].. ... ..R[A + B - 1]		*/
 
@@ -297,7 +297,7 @@
 OP_TFORCALL,/*	A C	R[A+4], ... ,R[A+3+C] := R[A](R[A+1], R[A+2]);	*/
 OP_TFORLOOP,/*	A Bx	if R[A+2] ~= nil then { R[A]=R[A+2]; pc -= Bx }	*/
 
-OP_SETLIST,/*	A B C k	R[A][(C-1)*FPF+i] := R[A+i], 1 <= i <= B	*/
+OP_SETLIST,/*	A B C k	R[A][C+i] := R[A+i], 1 <= i <= B		*/
 
 OP_CLOSURE,/*	A Bx	R[A] := closure(KPROTO[Bx])			*/
 
diff --git a/testes/locals.lua b/testes/locals.lua
index f5e9624..df44b86 100644
--- a/testes/locals.lua
+++ b/testes/locals.lua
@@ -246,6 +246,11 @@
 
   X = false
   foo = function (x)
+    local _<close> = func2close(function ()
+      -- without errors, enclosing function should be still active when
+      -- __close is called
+      assert(debug.getinfo(2).name == "foo")
+    end)
     local  _<close> = closescope
     local y = 15
     return y
@@ -343,6 +348,18 @@
 end
 
 
+-- errors inside __close can generate a warning instead of an
+-- error. This new 'assert' force them to appear.
+local function assert(cond, msg)
+  if not cond then
+    local line = debug.getinfo(2).currentline or "?"
+    msg = string.format("assertion failed! line %d (%s)\n", line, msg or "")
+    io.stderr:write(msg)
+    os.exit(1)
+  end
+end
+
+
 local function checkwarn (msg)
   if T then
     assert(string.find(_WARN, msg))
@@ -406,11 +423,15 @@
 
     local x <close> =
       func2close(function (self, msg)
+        -- after error, 'foo' was discarded, so caller now
+        -- must be 'pcall'
+        assert(debug.getinfo(2).name == "pcall")
         assert(msg == 4)
       end)
 
     local x1 <close> =
       func2close(function (self, msg)
+        assert(debug.getinfo(2).name == "pcall")
         checkwarn("@y")
         assert(msg == 4)
         error("@x1")
@@ -420,6 +441,7 @@
 
     local y <close> =
       func2close(function (self, msg)
+        assert(debug.getinfo(2).name == "pcall")
         assert(msg == 4)   -- error in body
         checkwarn("@z")
         error("@y")
@@ -428,6 +450,7 @@
     local first = true
     local z <close> =
       func2close(function (self, msg)
+        assert(debug.getinfo(2).name == "pcall")
         -- 'z' close is called once
         assert(first and msg == 4)
         first = false