From 28827e61d153e39ad3fe1e6fecbf27c09140fe75 Mon Sep 17 00:00:00 2001 From: nobu Date: Mon, 6 Aug 2012 15:31:13 +0000 Subject: method in instance_eval * class.c (rb_special_singleton_class_of): utility function. * vm_eval.c (eval_under): special deal for class variable scope with instance_eval. * vm_eval.c (rb_obj_instance_eval, rb_obj_instance_exec): allow method definition in instance_eval of special constants. [ruby-core:28324] [Bug #2788] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36647 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 11 +++++++++++ bootstraptest/test_eval.rb | 26 ++++++++++---------------- class.c | 24 +++++++++++++++++++----- internal.h | 1 + test/ruby/test_eval.rb | 15 +++++++++++++++ vm_eval.c | 7 +++++-- 6 files changed, 61 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8f84e58407..6dd6d81575 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +Tue Aug 7 00:31:09 2012 Nobuyoshi Nakada + + * class.c (rb_special_singleton_class_of): utility function. + + * vm_eval.c (eval_under): special deal for class variable scope with + instance_eval. + + * vm_eval.c (rb_obj_instance_eval, rb_obj_instance_exec): allow method + definition in instance_eval of special constants. [ruby-core:28324] + [Bug #2788] + Tue Aug 7 00:23:58 2012 Nobuyoshi Nakada * variable.c (CVAR_LOOKUP): split into helper functions. diff --git a/bootstraptest/test_eval.rb b/bootstraptest/test_eval.rb index aab1a7b1a4..bf7478006d 100644 --- a/bootstraptest/test_eval.rb +++ b/bootstraptest/test_eval.rb @@ -264,24 +264,18 @@ assert_equal 'ok', %q{ }, '[ruby-core:16794]' assert_equal 'ok', %q{ - begin - nil.instance_eval { - def a() :a end - } - rescue TypeError - :ok - end -}, '[ruby-core:16796]' + nil.instance_eval { + def defd_using_instance_eval() :ok end + } + nil.defd_using_instance_eval +}, '[ruby-core:28324]' assert_equal 'ok', %q{ - begin - nil.instance_exec { - def a() :a end - } - rescue TypeError - :ok - end -}, '[ruby-core:16796]' + nil.instance_exec { + def defd_using_instance_exec() :ok end + } + nil.defd_using_instance_exec +}, '[ruby-core:28324]' assert_normal_exit %q{ eval("", method(:proc).call {}.binding) diff --git a/class.c b/class.c index 4acdc0807d..2ee5b8867a 100644 --- a/class.c +++ b/class.c @@ -1286,6 +1286,20 @@ rb_undef_method(VALUE klass, const char *name) }\ } while (0) +static inline VALUE +special_singleton_class_of(VALUE obj) +{ + SPECIAL_SINGLETON(Qnil, rb_cNilClass); + SPECIAL_SINGLETON(Qfalse, rb_cFalseClass); + SPECIAL_SINGLETON(Qtrue, rb_cTrueClass); + return Qnil; +} + +VALUE +rb_special_singleton_class(VALUE obj) +{ + return special_singleton_class_of(obj); +} /*! * \internal @@ -1304,11 +1318,11 @@ singleton_class_of(VALUE obj) if (FIXNUM_P(obj) || SYMBOL_P(obj)) { rb_raise(rb_eTypeError, "can't define singleton"); } - if (rb_special_const_p(obj)) { - SPECIAL_SINGLETON(Qnil, rb_cNilClass); - SPECIAL_SINGLETON(Qfalse, rb_cFalseClass); - SPECIAL_SINGLETON(Qtrue, rb_cTrueClass); - rb_bug("unknown immediate %p", (void *)obj); + if (SPECIAL_CONST_P(obj)) { + klass = special_singleton_class_of(obj); + if (NIL_P(klass)) + rb_bug("unknown immediate %p", (void *)obj); + return klass; } if (FL_TEST(RBASIC(obj)->klass, FL_SINGLETON) && diff --git a/internal.h b/internal.h index 8396b0aad9..57b485d74f 100644 --- a/internal.h +++ b/internal.h @@ -60,6 +60,7 @@ VALUE rb_obj_protected_methods(int argc, VALUE *argv, VALUE obj); VALUE rb_obj_private_methods(int argc, VALUE *argv, VALUE obj); VALUE rb_obj_public_methods(int argc, VALUE *argv, VALUE obj); int rb_obj_basic_to_s_p(VALUE); +VALUE rb_special_singleton_class(VALUE); void Init_class_hierarchy(void); /* compile.c */ diff --git a/test/ruby/test_eval.rb b/test/ruby/test_eval.rb index fe97cd48cb..c24e4fa948 100644 --- a/test/ruby/test_eval.rb +++ b/test/ruby/test_eval.rb @@ -200,6 +200,21 @@ class TestEval < Test::Unit::TestCase end end + def test_instance_eval_method + bug2788 = '[ruby-core:28324]' + [Object.new, [], nil, true, false].each do |o| + assert_nothing_raised(TypeError, "#{bug2788} (#{o.inspect})") do + o.instance_eval { + def defd_using_instance_eval() :ok end + } + end + assert_equal(:ok, o.defd_using_instance_eval) + class << o + remove_method :defd_using_instance_eval + end + end + end + # # From ruby/test/ruby/test_eval.rb # diff --git a/vm_eval.c b/vm_eval.c index d1bc93b697..216607e439 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -1320,6 +1320,9 @@ eval_under(VALUE under, VALUE self, VALUE src, const char *file, int line) { NODE *cref = vm_cref_push(GET_THREAD(), under, NOEX_PUBLIC, NULL); + if (FL_TEST(under, FL_SINGLETON) || (SPECIAL_CONST_P(self) && !NIL_P(under))) { + cref->flags |= NODE_FL_CREF_PUSHED_BY_EVAL; + } if (rb_safe_level() >= 4) { StringValue(src); } @@ -1387,7 +1390,7 @@ rb_obj_instance_eval(int argc, VALUE *argv, VALUE self) VALUE klass; if (SPECIAL_CONST_P(self)) { - klass = Qnil; + klass = rb_special_singleton_class(self); } else { klass = rb_singleton_class(self); @@ -1419,7 +1422,7 @@ rb_obj_instance_exec(int argc, VALUE *argv, VALUE self) VALUE klass; if (SPECIAL_CONST_P(self)) { - klass = Qnil; + klass = rb_special_singleton_class(self); } else { klass = rb_singleton_class(self); -- cgit v1.2.3