Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions test/ruby/test_super.rb
Original file line number Diff line number Diff line change
Expand Up @@ -759,4 +759,19 @@ def initialize
inherited = inherited_class.new
assert_equal 2, inherited.test # it may read index=1 while it should be index=2
end

def test_super_in_basic_object
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
class ::BasicObject
def no_super
super()
rescue ::NameError
:ok
end
end

assert_equal :ok, "[Bug #21694]".no_super
end;
end
end
25 changes: 19 additions & 6 deletions vm_callinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ struct rb_callcache {
#define VM_CALLCACHE_REFINEMENT IMEMO_FL_USER3
#define VM_CALLCACHE_UNMARKABLE IMEMO_FL_USER4
#define VM_CALLCACHE_ON_STACK IMEMO_FL_USER5
#define VM_CALLCACHE_INVALID_SUPER IMEMO_FL_USER6

enum vm_cc_type {
cc_type_normal, // chained from ccs
Expand Down Expand Up @@ -344,8 +345,6 @@ vm_cc_new(VALUE klass,
*((struct rb_callable_method_entry_struct **)&cc->cme_) = (struct rb_callable_method_entry_struct *)cme;
*((vm_call_handler *)&cc->call_) = call;

VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_ICLASS));

switch (type) {
case cc_type_normal:
break;
Expand All @@ -358,8 +357,13 @@ vm_cc_new(VALUE klass,
break;
}

if (cme->def->type == VM_METHOD_TYPE_ATTRSET || cme->def->type == VM_METHOD_TYPE_IVAR) {
vm_cc_attr_index_initialize(cc, INVALID_SHAPE_ID);
if (cme) {
if (cme->def->type == VM_METHOD_TYPE_ATTRSET || cme->def->type == VM_METHOD_TYPE_IVAR) {
vm_cc_attr_index_initialize(cc, INVALID_SHAPE_ID);
}
}
else {
*(VALUE *)&cc->flags |= VM_CALLCACHE_INVALID_SUPER;
}

RB_DEBUG_COUNTER_INC(cc_new);
Expand Down Expand Up @@ -405,6 +409,14 @@ vm_cc_markable(const struct rb_callcache *cc)
return FL_TEST_RAW((VALUE)cc, VM_CALLCACHE_UNMARKABLE) == 0;
}

static inline bool
vm_cc_invalid_super(const struct rb_callcache *cc)
{
VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
// Set when calling super and there is no superclass.
return FL_TEST_RAW((VALUE)cc, VM_CALLCACHE_INVALID_SUPER);
}

static inline bool
vm_cc_valid(const struct rb_callcache *cc)
{
Expand All @@ -418,10 +430,11 @@ static inline const struct rb_callable_method_entry_struct *
vm_cc_cme(const struct rb_callcache *cc)
{
VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
VM_ASSERT(cc->klass != Qundef || !vm_cc_markable(cc));
VM_ASSERT(cc->klass != Qundef || !vm_cc_markable(cc) || vm_cc_invalid_super(cc));
VM_ASSERT(cc_check_class(cc->klass));
VM_ASSERT(cc->call_ == NULL || // not initialized yet
!vm_cc_markable(cc) ||
vm_cc_invalid_super(cc) ||
cc->cme_ != NULL);

return cc->cme_;
Expand All @@ -432,7 +445,7 @@ vm_cc_call(const struct rb_callcache *cc)
{
VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
VM_ASSERT(cc->call_ != NULL);
VM_ASSERT(cc->klass != Qundef || !vm_cc_markable(cc));
VM_ASSERT(cc->klass != Qundef || !vm_cc_markable(cc) || vm_cc_invalid_super(cc));
VM_ASSERT(cc_check_class(cc->klass));
return cc->call_;
}
Expand Down
2 changes: 1 addition & 1 deletion vm_insnhelper.c
Original file line number Diff line number Diff line change
Expand Up @@ -5164,7 +5164,7 @@ vm_search_super_method(const rb_control_frame_t *reg_cfp, struct rb_call_data *c

if (!klass) {
/* bound instance method of module */
cc = vm_cc_new(klass, NULL, vm_call_method_missing, cc_type_super);
cc = vm_cc_new(Qundef, NULL, vm_call_method_missing, cc_type_super);
RB_OBJ_WRITE(reg_cfp->iseq, &cd->cc, cc);
}
else {
Expand Down