mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
Show where mutated chilled strings were allocated
[Feature #20205] The warning now suggests running with --debug-frozen-string-literal: ``` test.rb:3: warning: literal string will be frozen in the future (run with --debug-frozen-string-literal for more information) ``` When using --debug-frozen-string-literal, the location where the string was created is shown: ``` test.rb:3: warning: literal string will be frozen in the future test.rb:1: info: the string was created here ``` When resurrecting strings and debug mode is not enabled, the overhead is a simple FL_TEST_RAW. When mutating chilled strings and deprecation warnings are not enabled, the overhead is a simple warning category enabled check. Co-authored-by: Jean Boussier <byroot@ruby-lang.org> Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org> Co-authored-by: Jean Boussier <byroot@ruby-lang.org>
This commit is contained in:
parent
75ef89ca16
commit
257f78fb67
Notes:
git
2024-10-21 10:33:20 +00:00
9 changed files with 144 additions and 77 deletions
57
error.c
57
error.c
|
@ -3973,13 +3973,25 @@ inspect_frozen_obj(VALUE obj, VALUE mesg, int recur)
|
|||
return mesg;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
get_created_info(VALUE obj, int *pline)
|
||||
{
|
||||
VALUE info = rb_attr_get(obj, id_debug_created_info);
|
||||
|
||||
if (NIL_P(info)) return Qnil;
|
||||
|
||||
VALUE path = rb_ary_entry(info, 0);
|
||||
VALUE line = rb_ary_entry(info, 1);
|
||||
if (NIL_P(path)) return Qnil;
|
||||
*pline = NUM2INT(line);
|
||||
return StringValue(path);
|
||||
}
|
||||
|
||||
void
|
||||
rb_error_frozen_object(VALUE frozen_obj)
|
||||
{
|
||||
rb_yjit_lazy_push_frame(GET_EC()->cfp->pc);
|
||||
|
||||
VALUE debug_info;
|
||||
const ID created_info = id_debug_created_info;
|
||||
VALUE mesg = rb_sprintf("can't modify frozen %"PRIsVALUE": ",
|
||||
CLASS_OF(frozen_obj));
|
||||
VALUE exc = rb_exc_new_str(rb_eFrozenError, mesg);
|
||||
|
@ -3987,15 +3999,46 @@ rb_error_frozen_object(VALUE frozen_obj)
|
|||
rb_ivar_set(exc, id_recv, frozen_obj);
|
||||
rb_exec_recursive(inspect_frozen_obj, frozen_obj, mesg);
|
||||
|
||||
if (!NIL_P(debug_info = rb_attr_get(frozen_obj, created_info))) {
|
||||
VALUE path = rb_ary_entry(debug_info, 0);
|
||||
VALUE line = rb_ary_entry(debug_info, 1);
|
||||
|
||||
rb_str_catf(mesg, ", created at %"PRIsVALUE":%"PRIsVALUE, path, line);
|
||||
int created_line;
|
||||
VALUE created_path = get_created_info(frozen_obj, &created_line);
|
||||
if (!NIL_P(created_path)) {
|
||||
rb_str_catf(mesg, ", created at %"PRIsVALUE":%d", created_path, created_line);
|
||||
}
|
||||
rb_exc_raise(exc);
|
||||
}
|
||||
|
||||
void
|
||||
rb_warn_unchilled(VALUE obj)
|
||||
{
|
||||
rb_warning_category_t category = RB_WARN_CATEGORY_DEPRECATED;
|
||||
if (!NIL_P(ruby_verbose) && rb_warning_category_enabled_p(category)) {
|
||||
int line;
|
||||
VALUE file = rb_source_location(&line);
|
||||
VALUE mesg = NIL_P(file) ? rb_str_new(0, 0) : rb_str_dup(file);
|
||||
|
||||
if (!NIL_P(file)) {
|
||||
if (line) rb_str_catf(mesg, ":%d", line);
|
||||
rb_str_cat2(mesg, ": ");
|
||||
}
|
||||
rb_str_cat2(mesg, "warning: literal string will be frozen in the future");
|
||||
|
||||
VALUE str = obj;
|
||||
if (STR_SHARED_P(str)) {
|
||||
str = RSTRING(obj)->as.heap.aux.shared;
|
||||
}
|
||||
VALUE created = get_created_info(str, &line);
|
||||
if (NIL_P(created)) {
|
||||
rb_str_cat2(mesg, " (run with --debug-frozen-string-literal for more information)\n");
|
||||
} else {
|
||||
rb_str_cat2(mesg, "\n");
|
||||
rb_str_append(mesg, created);
|
||||
if (line) rb_str_catf(mesg, ":%d", line);
|
||||
rb_str_cat2(mesg, ": info: the string was created here\n");
|
||||
}
|
||||
rb_warn_category(mesg, rb_warning_category_to_name(category));
|
||||
}
|
||||
}
|
||||
|
||||
#undef rb_check_frozen
|
||||
void
|
||||
rb_check_frozen(VALUE obj)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue