Bug #11718 ยป nil-const-access-11718.patch
compile.c | ||
---|---|---|
switch (nd_type(node)) {
|
||
case NODE_CONST:
|
||
debugi("compile_const_prefix - colon", node->nd_vid);
|
||
ADD_INSN1(body, nd_line(node), putobject, Qtrue);
|
||
ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_vid));
|
||
break;
|
||
case NODE_COLON3:
|
||
debugi("compile_const_prefix - colon3", node->nd_mid);
|
||
ADD_INSN(body, nd_line(node), pop);
|
||
ADD_INSN1(body, nd_line(node), putobject, rb_cObject);
|
||
ADD_INSN1(body, nd_line(node), putobject, Qtrue);
|
||
ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_mid));
|
||
break;
|
||
case NODE_COLON2:
|
||
CHECK(compile_const_prefix(iseq, node->nd_head, pref, body));
|
||
debugi("compile_const_prefix - colon2", node->nd_mid);
|
||
ADD_INSN1(body, nd_line(node), putobject, Qfalse);
|
||
ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_mid));
|
||
break;
|
||
default:
|
||
... | ... | |
ADD_INSNL(ret, line, branchunless, lassign); /* cref */
|
||
}
|
||
ADD_INSN(ret, line, dup); /* cref cref */
|
||
ADD_INSN1(ret, line, putobject, Qtrue);
|
||
ADD_INSN1(ret, line, getconstant, ID2SYM(mid)); /* cref obj */
|
||
if (node->nd_aid == idOROP || node->nd_aid == idANDOP) {
|
||
... | ... | |
int ic_index = body->is_size++;
|
||
ADD_INSN2(ret, line, opt_getinlinecache, lend, INT2FIX(ic_index));
|
||
ADD_INSN1(ret, line, putobject, Qtrue);
|
||
ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_vid));
|
||
ADD_INSN1(ret, line, opt_setinlinecache, INT2FIX(ic_index));
|
||
ADD_LABEL(ret, lend);
|
||
}
|
||
else {
|
||
ADD_INSN(ret, line, putnil);
|
||
ADD_INSN1(ret, line, putobject, Qtrue);
|
||
ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_vid));
|
||
}
|
||
... | ... | |
}
|
||
ADD_INSN1(ret, line, putobject, rb_cObject);
|
||
ADD_INSN1(ret, line, putobject, Qtrue);
|
||
ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_mid));
|
||
if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
|
insns.def | ||
---|---|---|
rb_cvar_set(vm_get_cvar_base(vm_get_cref(GET_EP()), GET_CFP()), id, val);
|
||
}
|
||
/* Get constant variable id. If klass is Qnil, constants
|
||
/* Get constant variable id. If klass is Qnil and allow_nil is Qtrue, constants
|
||
are searched in the current scope. Otherwise, get constant under klass
|
||
class or module.
|
||
*/
|
||
DEFINE_INSN
|
||
getconstant
|
||
(ID id)
|
||
(VALUE klass)
|
||
(VALUE klass, VALUE allow_nil)
|
||
(VALUE val)
|
||
/* getconstant can kick autoload */
|
||
// attr bool leaf = false; /* has rb_autoload_load() */
|
||
{
|
||
val = vm_get_ev_const(ec, klass, id, 0);
|
||
val = vm_get_ev_const(ec, klass, id, allow_nil == Qtrue, 0);
|
||
}
|
||
/* Set constant variable id under cbase class or module.
|
test/ruby/test_const.rb | ||
---|---|---|
assert_equal 8, TEST4
|
||
end
|
||
def test_const_access_from_nil
|
||
assert_raise(TypeError) { eval("nil::Object") }
|
||
assert_raise(TypeError) { eval("c = nil; c::Object") }
|
||
assert_raise(TypeError) { eval("sc = Class.new; sc::C = nil; sc::C::Object") }
|
||
end
|
||
def test_redefinition
|
||
c = Class.new
|
||
name = "X\u{5b9a 6570}"
|
vm_insnhelper.c | ||
---|---|---|
}
|
||
static inline VALUE
|
||
vm_get_ev_const(rb_execution_context_t *ec, VALUE orig_klass, ID id, int is_defined)
|
||
vm_get_ev_const(rb_execution_context_t *ec, VALUE orig_klass, ID id, int allow_nil, int is_defined)
|
||
{
|
||
void rb_const_warn_if_deprecated(const rb_const_entry_t *ce, VALUE klass, ID id);
|
||
VALUE val;
|
||
if (orig_klass == Qnil) {
|
||
if (orig_klass == Qnil && allow_nil) {
|
||
/* in current lexical scope */
|
||
const rb_cref_t *root_cref = vm_get_cref(ec->cfp->ep);
|
||
const rb_cref_t *cref;
|
||
... | ... | |
}
|
||
case DEFINED_CONST:
|
||
klass = v;
|
||
if (vm_get_ev_const(ec, klass, SYM2ID(obj), 1)) {
|
||
if (vm_get_ev_const(ec, klass, SYM2ID(obj), 1, 1)) {
|
||
expr_type = DEFINED_CONST;
|
||
}
|
||
break;
|