summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compile.c23
-rw-r--r--test/ruby/test_method.rb14
-rw-r--r--vm.c1
-rw-r--r--vm_core.h1
-rw-r--r--vm_insnhelper.c16
5 files changed, 44 insertions, 11 deletions
diff --git a/compile.c b/compile.c
index b980d6a32c..853fadf5b0 100644
--- a/compile.c
+++ b/compile.c
@@ -1998,6 +1998,19 @@ iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
return arg_size;
}
+static void
+iseq_set_use_block(rb_iseq_t *iseq)
+{
+ struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
+ if (!body->param.flags.use_block) {
+ body->param.flags.use_block = 1;
+
+ rb_vm_t *vm = GET_VM();
+ st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
+ st_insert(vm->unused_block_warning_table, key, 1);
+ }
+}
+
static int
iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
{
@@ -2099,7 +2112,7 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
if (block_id) {
body->param.block_start = arg_size++;
body->param.flags.has_block = TRUE;
- body->param.flags.use_block = 1;
+ iseq_set_use_block(iseq);
}
iseq_calc_param_size(iseq);
@@ -5920,7 +5933,7 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
ADD_INSN(ret, line_node, putnil);
ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
PUSH_VAL(DEFINED_YIELD));
- ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.use_block = 1;
+ iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
return;
case NODE_BACK_REF:
@@ -8632,7 +8645,7 @@ compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
}
else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
- ISEQ_BODY(iseq)->param.flags.use_block = 1;
+ iseq_set_use_block(iseq);
}
else {
goto unknown_arg;
@@ -9481,7 +9494,7 @@ compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
}
if (use_block && parent_block == NULL) {
- ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.use_block = 1;
+ iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
}
flag |= VM_CALL_SUPER | VM_CALL_FCALL;
@@ -9527,7 +9540,7 @@ compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
ADD_SEQ(ret, args);
ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
- ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.use_block = 1;
+ iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
if (popped) {
ADD_INSN(ret, node, pop);
diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb
index a41704cf06..5301b51650 100644
--- a/test/ruby/test_method.rb
+++ b/test/ruby/test_method.rb
@@ -1692,5 +1692,19 @@ class TestMethod < Test::Unit::TestCase
assert_match(/-:23: warning.+f5/, err.join)
assert_match(/-:24: warning.+f6/, err.join)
end
+
+ assert_in_out_err '-w', <<-'RUBY' do |_out, err, _status|
+ class C0
+ def f = yield
+ end
+
+ class C1 < C0
+ def f = nil
+ end
+
+ C1.new.f{} # do not warn on duck typing
+ RUBY
+ assert_equal 0, err.size, err.join("\n")
+ end
end
end
diff --git a/vm.c b/vm.c
index 3fb57e2eb6..cf2bed84e4 100644
--- a/vm.c
+++ b/vm.c
@@ -4254,6 +4254,7 @@ Init_BareVM(void)
vm->negative_cme_table = rb_id_table_create(16);
vm->overloaded_cme_table = st_init_numtable();
vm->constant_cache = rb_id_table_create(0);
+ vm->unused_block_warning_table = st_init_numtable();
// setup main thread
th->nt = ZALLOC(struct rb_native_thread);
diff --git a/vm_core.h b/vm_core.h
index 9d6f8d87d0..2400b02c7e 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -773,6 +773,7 @@ typedef struct rb_vm_struct {
st_table *ci_table;
struct rb_id_table *negative_cme_table;
st_table *overloaded_cme_table; // cme -> overloaded_cme
+ st_table *unused_block_warning_table;
// This id table contains a mapping from ID to ICs. It does this with ID
// keys and nested st_tables as values. The nested tables have ICs as keys
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 00cd709526..84ef212053 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -2971,9 +2971,9 @@ VALUE rb_gen_method_name(VALUE owner, VALUE name); // in vm_backtrace.c
static void
warn_unused_block(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq, void *pc)
{
- static st_table *dup_check_table = NULL;
+ rb_vm_t *vm = GET_VM();
+ st_table *dup_check_table = vm->unused_block_warning_table;
- st_data_t key = 0;
union {
VALUE v;
unsigned char b[SIZEOF_VALUE];
@@ -2983,6 +2983,14 @@ warn_unused_block(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq,
.v = (VALUE)cme->def,
};
+ // relax check
+ st_data_t key = (st_data_t)cme->def->original_id;
+
+ if (st_lookup(dup_check_table, key, NULL)) {
+ return;
+ }
+
+ // strict check
// make unique key from pc and me->def pointer
for (int i=0; i<SIZEOF_VALUE; i++) {
// fprintf(stderr, "k1:%3d k2:%3d\n", k1.b[i], k2.b[SIZEOF_VALUE-1-i]);
@@ -2995,10 +3003,6 @@ warn_unused_block(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq,
fprintf(stderr, "key:%p\n", (void *)key);
}
- if (!dup_check_table) {
- dup_check_table = st_init_numtable();
- }
-
// duplication check
if (st_insert(dup_check_table, key, 1)) {
// already shown