summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog11
-rw-r--r--bootstraptest/test_eval.rb26
-rw-r--r--class.c24
-rw-r--r--internal.h1
-rw-r--r--test/ruby/test_eval.rb15
-rw-r--r--vm_eval.c7
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 <nobu@ruby-lang.org>
+
+ * 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 <nobu@ruby-lang.org>
* 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);