diff --git a/compile.c b/compile.c index 7f2fd17f1f..eea013befd 100644 --- a/compile.c +++ b/compile.c @@ -4404,18 +4404,18 @@ compile_const_prefix(rb_iseq_t *iseq, const NODE *const node, switch (nd_type(node)) { case NODE_CONST: debugi("compile_const_prefix - colon", node->nd_vid); - ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_vid)); + ADD_INSN2(body, nd_line(node), getconstant, ID2SYM(node->nd_vid), 1); 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), getconstant, ID2SYM(node->nd_mid)); + ADD_INSN2(body, nd_line(node), getconstant, ID2SYM(node->nd_mid), 1); 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), getconstant, ID2SYM(node->nd_mid)); + ADD_INSN2(body, nd_line(node), getconstant, ID2SYM(node->nd_mid), 0); break; default: CHECK(COMPILE(pref, "const colon2 prefix", node)); @@ -7154,7 +7154,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in ADD_INSNL(ret, line, branchunless, lassign); /* cref */ } ADD_INSN(ret, line, dup); /* cref cref */ - ADD_INSN1(ret, line, getconstant, ID2SYM(mid)); /* cref obj */ + ADD_INSN2(ret, line, getconstant, ID2SYM(mid), 1); /* cref obj */ if (node->nd_aid == idOROP || node->nd_aid == idANDOP) { lfin = NEW_LABEL(line); @@ -7500,13 +7500,13 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in int ic_index = body->is_size++; ADD_INSN2(ret, line, opt_getinlinecache, lend, INT2FIX(ic_index)); - ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_vid)); + ADD_INSN2(ret, line, getconstant, ID2SYM(node->nd_vid), 1); ADD_INSN1(ret, line, opt_setinlinecache, INT2FIX(ic_index)); ADD_LABEL(ret, lend); } else { ADD_INSN(ret, line, putnil); - ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_vid)); + ADD_INSN2(ret, line, getconstant, ID2SYM(node->nd_vid), 1); } if (popped) { @@ -7893,7 +7893,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in } ADD_INSN1(ret, line, putobject, rb_cObject); - ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_mid)); + ADD_INSN2(ret, line, getconstant, ID2SYM(node->nd_mid), 1); if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) { ADD_INSN1(ret, line, opt_setinlinecache, INT2FIX(ic_index)); diff --git a/insns.def b/insns.def index 6cfb3b121f..e84fcecfe7 100644 --- a/insns.def +++ b/insns.def @@ -252,19 +252,19 @@ setclassvariable 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 true, constants are searched in the current scope. Otherwise, get constant under klass class or module. */ DEFINE_INSN getconstant -(ID id) +(ID id, VALUE allow_nil) (VALUE klass) (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, 0); } /* Set constant variable id under cbase class or module. diff --git a/test/ruby/test_const.rb b/test/ruby/test_const.rb index 8784e0e988..6284434db0 100644 --- a/test/ruby/test_const.rb +++ b/test/ruby/test_const.rb @@ -48,6 +48,12 @@ class TestConst < Test::Unit::TestCase 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}" diff --git a/vm_insnhelper.c b/vm_insnhelper.c index cc38a0dc4b..1b985f4e8d 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -890,12 +890,12 @@ vm_get_iclass(rb_control_frame_t *cfp, VALUE klass) } 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; @@ -3146,7 +3146,7 @@ vm_defined(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, rb_num_t op_ } 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;