Moving functions out of a loop is not as simple as you think: the loop may not be visible at all and come from an invisible outer scope. The new function declaration will be made incide a deep call.
If then that function declaration automatically inherits many upvalues that are useless, there will always be a new function created at each call. And this makes no sense.
Eliminating all useless upvalues (even if they are in lexical scope) from the set of upvalues is then necessary: if at least this set of upvalues is now empty, it makes no sense at all to create a new closure at each call: a static closure should then be generated always by the compiler, without even having to lookup in a cache if there are other closures with the same set of upvalues (with the same effective reference to the same variable from the same outer scope).
Note also that if there are remaining upvalues in that set, the effective value of these variables is still mutable: nothing warranties it will be immutable, so the upvalues are normally variable references, not "constants", except if they are declared this way or by a deep inspection of varaible mutation within the lexical scope.
So I still maintain this is a bug for the exposed case: the set of upvalues is empty, the closure should then be static, and it does not need at all any cache.