summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compile.c6
-rw-r--r--iseq.c19
-rw-r--r--iseq.h3
-rw-r--r--test/ruby/test_const.rb5
-rw-r--r--tool/ruby_vm/views/_leaf_helpers.erb1
-rw-r--r--vm_insnhelper.c5
6 files changed, 28 insertions, 11 deletions
diff --git a/compile.c b/compile.c
index b45aaef6ee..f439abb947 100644
--- a/compile.c
+++ b/compile.c
@@ -4728,13 +4728,13 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
ADD_INSN3(ret, line, defined,
(rb_is_const_id(node->nd_mid) ?
- INT2FIX(DEFINED_CONST) : INT2FIX(DEFINED_METHOD)),
+ INT2FIX(DEFINED_CONST_FROM) : INT2FIX(DEFINED_METHOD)),
ID2SYM(node->nd_mid), needstr);
return;
case NODE_COLON3:
ADD_INSN1(ret, line, putobject, rb_cObject);
ADD_INSN3(ret, line, defined,
- INT2FIX(DEFINED_CONST), ID2SYM(node->nd_mid), needstr);
+ INT2FIX(DEFINED_CONST_FROM), ID2SYM(node->nd_mid), needstr);
return;
/* method dispatch */
@@ -7493,7 +7493,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
if (node->nd_aid == idOROP) {
lassign = NEW_LABEL(line);
ADD_INSN(ret, line, dup); /* cref cref */
- ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_CONST),
+ ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_CONST_FROM),
ID2SYM(mid), Qfalse); /* cref bool */
ADD_INSNL(ret, line, branchunless, lassign); /* cref */
}
diff --git a/iseq.c b/iseq.c
index 48a4d4b677..6c2d2256ff 100644
--- a/iseq.c
+++ b/iseq.c
@@ -1830,13 +1830,20 @@ rb_insn_operand_intern(const rb_iseq_t *iseq,
case TS_NUM: /* ULONG */
if (insn == BIN(defined) && op_no == 0) {
enum defined_type deftype = (enum defined_type)op;
- if (deftype == DEFINED_FUNC) {
- ret = rb_fstring_lit("func"); break;
- }
- if (deftype == DEFINED_REF) {
- ret = rb_fstring_lit("ref"); break;
+ switch (deftype) {
+ case DEFINED_FUNC:
+ ret = rb_fstring_lit("func");
+ break;
+ case DEFINED_REF:
+ ret = rb_fstring_lit("ref");
+ break;
+ case DEFINED_CONST_FROM:
+ ret = rb_fstring_lit("constant-from");
+ break;
+ default:
+ ret = rb_iseq_defined_string(deftype);
+ break;
}
- ret = rb_iseq_defined_string(deftype);
if (ret) break;
}
else if (insn == BIN(checktype) && op_no == 0) {
diff --git a/iseq.h b/iseq.h
index c9cc12529b..1fcf7cb210 100644
--- a/iseq.h
+++ b/iseq.h
@@ -300,7 +300,8 @@ enum defined_type {
DEFINED_EXPR,
DEFINED_IVAR2,
DEFINED_REF,
- DEFINED_FUNC
+ DEFINED_FUNC,
+ DEFINED_CONST_FROM
};
VALUE rb_iseq_defined_string(enum defined_type type);
diff --git a/test/ruby/test_const.rb b/test/ruby/test_const.rb
index 6284434db0..1c73b66648 100644
--- a/test/ruby/test_const.rb
+++ b/test/ruby/test_const.rb
@@ -50,8 +50,13 @@ class TestConst < Test::Unit::TestCase
def test_const_access_from_nil
assert_raise(TypeError) { eval("nil::Object") }
+ assert_nil eval("defined?(nil::Object)")
+
assert_raise(TypeError) { eval("c = nil; c::Object") }
+ assert_nil eval("c = nil; defined?(c::Object)")
+
assert_raise(TypeError) { eval("sc = Class.new; sc::C = nil; sc::C::Object") }
+ assert_nil eval("sc = Class.new; sc::C = nil; defined?(sc::C::Object)")
end
def test_redefinition
diff --git a/tool/ruby_vm/views/_leaf_helpers.erb b/tool/ruby_vm/views/_leaf_helpers.erb
index 12defa5bf6..ac60f2dcbc 100644
--- a/tool/ruby_vm/views/_leaf_helpers.erb
+++ b/tool/ruby_vm/views/_leaf_helpers.erb
@@ -81,6 +81,7 @@ leafness_of_defined(rb_num_t op_type)
case DEFINED_ZSUPER:
return false;
case DEFINED_CONST:
+ case DEFINED_CONST_FROM:
/* has rb_autoload_load(); */
return false;
case DEFINED_FUNC:
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 5c83c343cc..205b4d915f 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -3477,11 +3477,14 @@ vm_defined(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, rb_num_t op_
break;
}
case DEFINED_CONST:
+ case DEFINED_CONST_FROM: {
+ bool allow_nil = type == DEFINED_CONST;
klass = v;
- if (vm_get_ev_const(ec, klass, SYM2ID(obj), 1, 1)) {
+ if (vm_get_ev_const(ec, klass, SYM2ID(obj), allow_nil, true)) {
expr_type = DEFINED_CONST;
}
break;
+ }
case DEFINED_FUNC:
klass = CLASS_OF(v);
if (rb_method_boundp(klass, SYM2ID(obj), 0)) {