aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog13
-rw-r--r--error.c11
-rw-r--r--test/ruby/test_exception.rb25
-rw-r--r--vm_core.h9
-rw-r--r--vm_eval.c11
-rw-r--r--vm_insnhelper.c4
-rw-r--r--vm_insnhelper.h4
7 files changed, 67 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index 52591cfaec..412a7d5aba 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+Sun Feb 28 13:40:46 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * error.c (nometh_err_initialize): add private_call? parameter.
+
+ * error.c (nometh_err_private_call_p): add private_call? method,
+ to tell if the exception raised in private form FCALL or VCALL.
+ [Feature #12043]
+
+ * vm_eval.c (make_no_method_exception): append private_call?
+ argument.
+
+ * vm_insnhelper.c (ci_missing_reason): copy FCALL flag.
+
Sun Feb 28 10:19:47 2016 Ryan T. Hosford <tad.hosford@gmail.com>
* array.c (rb_ary_and): clarify that set intersection returns the
diff --git a/error.c b/error.c
index 204a9a6302..93cb6f03d6 100644
--- a/error.c
+++ b/error.c
@@ -697,6 +697,7 @@ static VALUE rb_eNOERROR;
static ID id_new, id_cause, id_message, id_backtrace;
static ID id_name, id_args, id_Errno, id_errno, id_i_path;
static ID id_receiver, id_iseq, id_local_variables;
+static ID id_private_call_p;
extern ID ruby_static_id_status;
#define id_bt idBt
#define id_bt_locations idBt_locations
@@ -1203,9 +1204,11 @@ name_err_local_variables(VALUE self)
static VALUE
nometh_err_initialize(int argc, VALUE *argv, VALUE self)
{
+ VALUE priv = (argc > 3) && (--argc, RTEST(argv[argc])) ? Qtrue : Qfalse;
VALUE args = (argc > 2) ? argv[--argc] : Qnil;
name_err_initialize(argc, argv, self);
rb_ivar_set(self, id_args, args);
+ rb_ivar_set(self, id_private_call_p, RTEST(priv) ? Qtrue : Qfalse);
return self;
}
@@ -1392,6 +1395,12 @@ nometh_err_args(VALUE self)
return rb_attr_get(self, id_args);
}
+static VALUE
+nometh_err_private_call_p(VALUE self)
+{
+ return rb_attr_get(self, id_private_call_p);
+}
+
void
rb_invalid_str(const char *str, const char *type)
{
@@ -2019,6 +2028,7 @@ Init_Exception(void)
rb_eNoMethodError = rb_define_class("NoMethodError", rb_eNameError);
rb_define_method(rb_eNoMethodError, "initialize", nometh_err_initialize, -1);
rb_define_method(rb_eNoMethodError, "args", nometh_err_args, 0);
+ rb_define_method(rb_eNoMethodError, "private_call?", nometh_err_private_call_p, 0);
rb_eRuntimeError = rb_define_class("RuntimeError", rb_eStandardError);
rb_eSecurityError = rb_define_class("SecurityError", rb_eException);
@@ -2043,6 +2053,7 @@ Init_Exception(void)
id_name = rb_intern_const("name");
id_args = rb_intern_const("args");
id_receiver = rb_intern_const("receiver");
+ id_private_call_p = rb_intern_const("private_call?");
id_local_variables = rb_intern_const("local_variables");
id_Errno = rb_intern_const("Errno");
id_errno = rb_intern_const("errno");
diff --git a/test/ruby/test_exception.rb b/test/ruby/test_exception.rb
index 7c0674857a..262d27f080 100644
--- a/test/ruby/test_exception.rb
+++ b/test/ruby/test_exception.rb
@@ -762,6 +762,7 @@ end.join
assert_equal(:foo, e.name)
assert_equal([1, 2], e.args)
assert_same(obj, e.receiver)
+ assert_not_predicate(e, :private_call?)
e = assert_raise(NoMethodError) {
obj.instance_eval {foo(1, 2)}
@@ -769,6 +770,7 @@ end.join
assert_equal(:foo, e.name)
assert_equal([1, 2], e.args)
assert_same(obj, e.receiver)
+ assert_predicate(e, :private_call?)
end
def test_name_error_info_local_variables
@@ -787,6 +789,29 @@ end.join
assert_equal(%i[a b c d e f g], e.local_variables.sort)
end
+ def test_name_error_info_method_missing
+ obj = PrettyObject.new
+ def obj.method_missing(*)
+ super
+ end
+
+ e = assert_raise(NoMethodError) {
+ obj.foo(1, 2)
+ }
+ assert_equal(:foo, e.name)
+ assert_equal([1, 2], e.args)
+ assert_same(obj, e.receiver)
+ assert_not_predicate(e, :private_call?)
+
+ e = assert_raise(NoMethodError) {
+ obj.instance_eval {foo(1, 2)}
+ }
+ assert_equal(:foo, e.name)
+ assert_equal([1, 2], e.args)
+ assert_same(obj, e.receiver)
+ assert_predicate(e, :private_call?)
+ end
+
def test_name_error_info_parent_iseq_mark
assert_separately(['-', File.join(__dir__, 'bug-11928.rb')], <<-'end;')
-> {require ARGV[0]}.call
diff --git a/vm_core.h b/vm_core.h
index 38de35636f..8b5e853d57 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -200,10 +200,11 @@ enum method_missing_reason {
MISSING_NOENTRY = 0x00,
MISSING_PRIVATE = 0x01,
MISSING_PROTECTED = 0x02,
- MISSING_VCALL = 0x04,
- MISSING_SUPER = 0x08,
- MISSING_MISSING = 0x10,
- MISSING_NONE = 0x20
+ MISSING_FCALL = 0x04,
+ MISSING_VCALL = 0x08,
+ MISSING_SUPER = 0x10,
+ MISSING_MISSING = 0x20,
+ MISSING_NONE = 0x40
};
struct rb_call_info {
diff --git a/vm_eval.c b/vm_eval.c
index 5bdc948c75..7eda5c24d8 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -682,13 +682,15 @@ rb_method_missing(int argc, const VALUE *argv, VALUE obj)
}
static VALUE
-make_no_method_exception(VALUE exc, VALUE format, VALUE obj, int argc, const VALUE *argv)
+make_no_method_exception(VALUE exc, VALUE format, VALUE obj,
+ int argc, const VALUE *argv, int priv)
{
int n = 0;
enum {
arg_mesg,
arg_name,
arg_args,
+ arg_priv,
args_size
};
VALUE args[args_size];
@@ -700,6 +702,7 @@ make_no_method_exception(VALUE exc, VALUE format, VALUE obj, int argc, const VAL
args[n++] = argv[0];
if (exc == rb_eNoMethodError) {
args[n++] = rb_ary_new4(argc - 1, argv + 1);
+ args[n++] = priv ? Qtrue : Qfalse;
}
return rb_class_new_instance(n, args, exc);
}
@@ -737,7 +740,8 @@ raise_method_missing(rb_thread_t *th, int argc, const VALUE *argv, VALUE obj,
}
{
- exc = make_no_method_exception(exc, format, obj, argc, argv);
+ exc = make_no_method_exception(exc, format, obj, argc, argv,
+ last_call_status & (MISSING_FCALL|MISSING_VCALL));
if (!(last_call_status & MISSING_MISSING)) {
rb_vm_pop_cfunc_frame();
}
@@ -929,7 +933,8 @@ send_internal(int argc, const VALUE *argv, VALUE recv, call_type scope)
if (!id) {
if (rb_method_basic_definition_p(CLASS_OF(recv), idMethodMissing)) {
VALUE exc = make_no_method_exception(rb_eNoMethodError, 0,
- recv, argc, argv);
+ recv, argc, argv,
+ scope != CALL_PUBLIC);
rb_exc_raise(exc);
}
if (!SYMBOL_P(*argv)) {
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 022a64df12..39ca48a578 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1782,6 +1782,7 @@ ci_missing_reason(const struct rb_call_info *ci)
{
enum method_missing_reason stat = MISSING_NOENTRY;
if (ci->flag & VM_CALL_VCALL) stat |= MISSING_VCALL;
+ if (ci->flag & VM_CALL_FCALL) stat |= MISSING_FCALL;
if (ci->flag & VM_CALL_SUPER) stat |= MISSING_SUPER;
return stat;
}
@@ -1823,7 +1824,8 @@ vm_call_opt_send(rb_thread_t *th, rb_control_frame_t *reg_cfp, struct rb_calling
if (!(ci->mid = rb_check_id(&sym))) {
if (rb_method_basic_definition_p(CLASS_OF(calling->recv), idMethodMissing)) {
VALUE exc = make_no_method_exception(rb_eNoMethodError, 0, calling->recv,
- rb_long2int(calling->argc), &TOPN(i));
+ rb_long2int(calling->argc), &TOPN(i),
+ ci->flag & (VM_CALL_FCALL|VM_CALL_VCALL));
rb_exc_raise(exc);
}
TOPN(i) = rb_str_intern(sym);
diff --git a/vm_insnhelper.h b/vm_insnhelper.h
index f2a2a88c72..69eaaacf2e 100644
--- a/vm_insnhelper.h
+++ b/vm_insnhelper.h
@@ -185,8 +185,8 @@ enum vm_regan_acttype {
#define GET_GLOBAL_CONSTANT_STATE() (ruby_vm_global_constant_state)
#define INC_GLOBAL_CONSTANT_STATE() (++ruby_vm_global_constant_state)
-static VALUE make_no_method_exception(VALUE exc, VALUE format,
- VALUE obj, int argc, const VALUE *argv);
+static VALUE make_no_method_exception(VALUE exc, VALUE format, VALUE obj,
+ int argc, const VALUE *argv, int priv);
static inline struct vm_throw_data *
THROW_DATA_NEW(VALUE val, rb_control_frame_t *cf, VALUE st)