summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--class.c1
-rw-r--r--internal.h8
-rw-r--r--test/ruby/test_super.rb23
-rw-r--r--vm_insnhelper.c13
4 files changed, 39 insertions, 6 deletions
diff --git a/class.c b/class.c
index 736e227..4129647 100644
--- a/class.c
+++ b/class.c
@@ -921,6 +921,7 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super)
}
iclass = rb_include_class_new(module, RCLASS_SUPER(c));
c = RCLASS_SET_SUPER(c, iclass);
+ RCLASS_SET_INCLUDER(iclass, klass);
{
VALUE m = module;
diff --git a/internal.h b/internal.h
index 374db5c..3bd95c2 100644
--- a/internal.h
+++ b/internal.h
@@ -1039,6 +1039,7 @@ struct rb_classext_struct {
const VALUE origin_;
const VALUE refined_class;
rb_alloc_func_t allocator;
+ const VALUE includer;
};
typedef struct rb_classext_struct rb_classext_t;
@@ -1078,6 +1079,7 @@ int rb_singleton_class_internal_p(VALUE sklass);
#else
# define RCLASS_SERIAL(c) (RCLASS_EXT(c)->class_serial)
#endif
+#define RCLASS_INCLUDER(c) (RCLASS_EXT(c)->includer)
#define RCLASS_CLONED FL_USER6
#define RICLASS_IS_ORIGIN FL_USER5
@@ -1090,6 +1092,12 @@ RCLASS_SET_ORIGIN(VALUE klass, VALUE origin)
if (klass != origin) FL_SET(origin, RICLASS_IS_ORIGIN);
}
+static inline void
+RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass)
+{
+ RB_OBJ_WRITE(iclass, &RCLASS_INCLUDER(iclass), klass);
+}
+
#undef RCLASS_SUPER
static inline VALUE
RCLASS_SUPER(VALUE klass)
diff --git a/test/ruby/test_super.rb b/test/ruby/test_super.rb
index bb78ab5..bbfc581 100644
--- a/test/ruby/test_super.rb
+++ b/test/ruby/test_super.rb
@@ -307,6 +307,29 @@ class TestSuper < Test::Unit::TestCase
end
end
+ def test_super_in_instance_eval_in_module
+ super_class = EnvUtil.labeled_class("Super\u{30af 30e9 30b9}") {
+ def foo
+ return [:super, self]
+ end
+ }
+ mod = EnvUtil.labeled_module("Mod\u{30af 30e9 30b9}") {
+ def foo
+ x = Object.new
+ x.instance_eval do
+ super()
+ end
+ end
+ }
+ sub_class = EnvUtil.labeled_class("Sub\u{30af 30e9 30b9}", super_class) {
+ include mod
+ }
+ obj = sub_class.new
+ assert_raise_with_message(TypeError, /Sub\u{30af 30e9 30b9}/) do
+ obj.foo
+ end
+ end
+
def test_super_in_orphan_block
super_class = EnvUtil.labeled_class("Super\u{30af 30e9 30b9}") {
def foo
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index c8ea3f9..8487886 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -3126,16 +3126,17 @@ vm_search_super_method(const rb_control_frame_t *reg_cfp, struct rb_call_data *c
}
if (BUILTIN_TYPE(current_defined_class) != T_MODULE &&
- BUILTIN_TYPE(current_defined_class) != T_ICLASS && /* bound UnboundMethod */
!FL_TEST(current_defined_class, RMODULE_INCLUDED_INTO_REFINEMENT) &&
!rb_obj_is_kind_of(recv, current_defined_class)) {
VALUE m = RB_TYPE_P(current_defined_class, T_ICLASS) ?
- RBASIC(current_defined_class)->klass : current_defined_class;
+ RCLASS_INCLUDER(current_defined_class) : current_defined_class;
- rb_raise(rb_eTypeError,
- "self has wrong type to call super in this context: "
- "%"PRIsVALUE" (expected %"PRIsVALUE")",
- rb_obj_class(recv), m);
+ if (m) { /* not bound UnboundMethod */
+ rb_raise(rb_eTypeError,
+ "self has wrong type to call super in this context: "
+ "%"PRIsVALUE" (expected %"PRIsVALUE")",
+ rb_obj_class(recv), m);
+ }
}
if (me->def->type == VM_METHOD_TYPE_BMETHOD && (ci->flag & VM_CALL_ZSUPER)) {