summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKoichi Sasada <[email protected]>2024-11-06 03:41:59 +0900
committerKoichi Sasada <[email protected]>2024-11-06 11:06:18 +0900
commitab7ab9e4508c24b998703824aa9576fb2e092065 (patch)
tree27baa0a69fbdc59f54bf0526dde4c8c299ccbf82
parent4203c70dfa96649bae305350817d7cc3c9bc5888 (diff)
`Warning[:strict_unused_block]`
to show unused block warning strictly. ```ruby class C def f = nil end class D def f = yield end [C.new, D.new].each{|obj| obj.f{}} ``` In this case, `D#f` accepts a block. However `C#f` doesn't accept a block. There are some cases passing a block with `obj.f{}` where `obj` is `C` or `D`. To avoid warnings on such cases, "unused block warning" will be warned only if there is not same name which accepts a block. On the above example, `C.new.f{}` doesn't show any warnings because there is a same name `D#f` which accepts a block. We call this default behavior as "relax mode". `strict_unused_block` new warning category changes from "relax mode" to "strict mode", we don't check same name methods and `C.new.f{}` will be warned. [Feature #15554]
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/12005
-rw-r--r--compile.c2
-rw-r--r--error.c4
-rw-r--r--include/ruby/internal/error.h4
-rw-r--r--ruby.c4
-rw-r--r--test/ruby/test_rubyoptions.rb2
-rw-r--r--vm.c6
-rw-r--r--vm_core.h1
-rw-r--r--vm_insnhelper.c11
8 files changed, 20 insertions, 14 deletions
diff --git a/compile.c b/compile.c
index d1c86b3427..e777fba89a 100644
--- a/compile.c
+++ b/compile.c
@@ -2007,7 +2007,7 @@ iseq_set_use_block(rb_iseq_t *iseq)
rb_vm_t *vm = GET_VM();
- if (!vm->unused_block_warning_strict) {
+ if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
st_insert(vm->unused_block_warning_table, key, 1);
}
diff --git a/error.c b/error.c
index b6ed5d22d1..05c89fe8e8 100644
--- a/error.c
+++ b/error.c
@@ -86,6 +86,7 @@ static ID id_category;
static ID id_deprecated;
static ID id_experimental;
static ID id_performance;
+static ID id_strict_unused_block;
static VALUE sym_category;
static VALUE sym_highlight;
static struct {
@@ -3584,6 +3585,7 @@ Init_Exception(void)
id_deprecated = rb_intern_const("deprecated");
id_experimental = rb_intern_const("experimental");
id_performance = rb_intern_const("performance");
+ id_strict_unused_block = rb_intern_const("strict_unused_block");
id_top = rb_intern_const("top");
id_bottom = rb_intern_const("bottom");
id_iseq = rb_make_internal_id();
@@ -3596,12 +3598,14 @@ Init_Exception(void)
st_add_direct(warning_categories.id2enum, id_deprecated, RB_WARN_CATEGORY_DEPRECATED);
st_add_direct(warning_categories.id2enum, id_experimental, RB_WARN_CATEGORY_EXPERIMENTAL);
st_add_direct(warning_categories.id2enum, id_performance, RB_WARN_CATEGORY_PERFORMANCE);
+ st_add_direct(warning_categories.id2enum, id_strict_unused_block, RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK);
warning_categories.enum2id = rb_init_identtable();
st_add_direct(warning_categories.enum2id, RB_WARN_CATEGORY_NONE, 0);
st_add_direct(warning_categories.enum2id, RB_WARN_CATEGORY_DEPRECATED, id_deprecated);
st_add_direct(warning_categories.enum2id, RB_WARN_CATEGORY_EXPERIMENTAL, id_experimental);
st_add_direct(warning_categories.enum2id, RB_WARN_CATEGORY_PERFORMANCE, id_performance);
+ st_add_direct(warning_categories.enum2id, RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK, id_strict_unused_block);
}
void
diff --git a/include/ruby/internal/error.h b/include/ruby/internal/error.h
index cd37f4461a..3ff885b2b1 100644
--- a/include/ruby/internal/error.h
+++ b/include/ruby/internal/error.h
@@ -53,6 +53,9 @@ typedef enum {
/** Warning is for performance issues (not enabled by -w). */
RB_WARN_CATEGORY_PERFORMANCE,
+ /** Warning is for checking unused block strictly */
+ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK,
+
RB_WARN_CATEGORY_DEFAULT_BITS = (
(1U << RB_WARN_CATEGORY_DEPRECATED) |
(1U << RB_WARN_CATEGORY_EXPERIMENTAL) |
@@ -62,6 +65,7 @@ typedef enum {
(1U << RB_WARN_CATEGORY_DEPRECATED) |
(1U << RB_WARN_CATEGORY_EXPERIMENTAL) |
(1U << RB_WARN_CATEGORY_PERFORMANCE) |
+ (1U << RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK) |
0)
} rb_warning_category_t;
diff --git a/ruby.c b/ruby.c
index e95c01e8d0..6f32f11b57 100644
--- a/ruby.c
+++ b/ruby.c
@@ -398,6 +398,7 @@ usage(const char *name, int help, int highlight, int columns)
M("deprecated", "", "Deprecated features."),
M("experimental", "", "Experimental features."),
M("performance", "", "Performance issues."),
+ M("strict_unused_block", "", "Warning unused block strictly"),
};
#if USE_RJIT
extern const struct ruby_opt_message rb_rjit_option_messages[];
@@ -1233,6 +1234,9 @@ proc_W_option(ruby_cmdline_options_t *opt, const char *s, int *warning)
else if (NAME_MATCH_P("performance", s, len)) {
bits = 1U << RB_WARN_CATEGORY_PERFORMANCE;
}
+ else if (NAME_MATCH_P("strict_unused_block", s, len)) {
+ bits = 1U << RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK;
+ }
else {
rb_warn("unknown warning category: '%s'", s);
}
diff --git a/test/ruby/test_rubyoptions.rb b/test/ruby/test_rubyoptions.rb
index 55f38d3012..0a3d2990fc 100644
--- a/test/ruby/test_rubyoptions.rb
+++ b/test/ruby/test_rubyoptions.rb
@@ -118,7 +118,7 @@ class TestRubyOptions < Test::Unit::TestCase
assert_in_out_err(%w(-We) + ['p $-W'], "", %w(2), [])
assert_in_out_err(%w(-w -W0 -e) + ['p $-W'], "", %w(0), [])
- categories = {deprecated: 1, experimental: 0, performance: 2}
+ categories = {deprecated: 1, experimental: 0, performance: 2, strict_unused_block: 3}
assert_equal categories.keys.sort, Warning.categories.sort
categories.each do |category, level|
diff --git a/vm.c b/vm.c
index 54bbf4d7fd..3e9de4d215 100644
--- a/vm.c
+++ b/vm.c
@@ -4271,12 +4271,6 @@ Init_BareVM(void)
vm->constant_cache = rb_id_table_create(0);
vm->unused_block_warning_table = st_init_numtable();
- // TODO: remove before Ruby 3.4.0 release
- const char *s = getenv("RUBY_TRY_UNUSED_BLOCK_WARNING_STRICT");
- if (s && strcmp(s, "1") == 0) {
- vm->unused_block_warning_strict = true;
- }
-
// setup main thread
th->nt = ZALLOC(struct rb_native_thread);
th->vm = vm;
diff --git a/vm_core.h b/vm_core.h
index 459e800e39..398f771121 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -799,7 +799,6 @@ typedef struct rb_vm_struct {
struct rb_id_table *negative_cme_table;
st_table *overloaded_cme_table; // cme -> overloaded_cme
st_table *unused_block_warning_table;
- bool unused_block_warning_strict;
// 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 71583e60cd..bb33d42996 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -3035,6 +3035,7 @@ warn_unused_block(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq,
rb_vm_t *vm = GET_VM();
st_table *dup_check_table = vm->unused_block_warning_table;
st_data_t key;
+ bool strict_unused_block = rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK);
union {
VALUE v;
@@ -3046,7 +3047,7 @@ warn_unused_block(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq,
};
// relax check
- if (!vm->unused_block_warning_strict) {
+ if (!strict_unused_block) {
key = (st_data_t)cme->def->original_id;
if (st_lookup(dup_check_table, key, NULL)) {
@@ -3072,16 +3073,16 @@ warn_unused_block(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq,
if (st_insert(dup_check_table, key, 1)) {
// already shown
}
- else {
+ else if (RTEST(ruby_verbose) || strict_unused_block) {
VALUE m_loc = rb_method_entry_location((const rb_method_entry_t *)cme);
VALUE name = rb_gen_method_name(cme->defined_class, ISEQ_BODY(iseq)->location.base_label);
if (!NIL_P(m_loc)) {
- rb_warning("the block passed to '%"PRIsVALUE"' defined at %"PRIsVALUE":%"PRIsVALUE" may be ignored",
- name, RARRAY_AREF(m_loc, 0), RARRAY_AREF(m_loc, 1));
+ rb_warn("the block passed to '%"PRIsVALUE"' defined at %"PRIsVALUE":%"PRIsVALUE" may be ignored",
+ name, RARRAY_AREF(m_loc, 0), RARRAY_AREF(m_loc, 1));
}
else {
- rb_warning("the block may be ignored because '%"PRIsVALUE"' does not use a block", name);
+ rb_warn("the block may be ignored because '%"PRIsVALUE"' does not use a block", name);
}
}
}