summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2020-04-07 21:35:28 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2020-04-07 21:35:28 +0900
commit927308108cced69cae478798004524b9a5d2f252 (patch)
tree4ea06b5df2a5a59aa1dec8ec732a593484233fb9
parentce608213872d4efe80708f872ee2e32c547dd734 (diff)
Fix source location of autoloaded constant [Bug #16764]
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/3009
-rw-r--r--test/ruby/test_autoload.rb13
-rw-r--r--variable.c27
2 files changed, 32 insertions, 8 deletions
diff --git a/test/ruby/test_autoload.rb b/test/ruby/test_autoload.rb
index b3ccf183ec..d3470d59d4 100644
--- a/test/ruby/test_autoload.rb
+++ b/test/ruby/test_autoload.rb
@@ -427,6 +427,19 @@ p Foo::Bar
end
end
+ def test_source_location
+ klass = self.class
+ bug = "Bug16764"
+ Dir.mktmpdir('autoload') do |tmpdir|
+ path = "#{tmpdir}/test-#{bug}.rb"
+ File.write(path, "#{klass}::#{bug} = __FILE__\n")
+ klass.autoload(:Bug16764, path)
+ assert_equal [__FILE__, __LINE__-1], klass.const_source_location(bug)
+ assert_equal path, klass.const_get(bug)
+ assert_equal [path, 1], klass.const_source_location(bug)
+ end
+ end
+
def test_no_leak
assert_no_memory_leak([], '', <<~'end;', 'many autoloads', timeout: 60)
200000.times do |i|
diff --git a/variable.c b/variable.c
index aed71751c0..21559c1094 100644
--- a/variable.c
+++ b/variable.c
@@ -1807,8 +1807,10 @@ struct autoload_const {
VALUE mod;
VALUE ad; /* autoload_data_i */
VALUE value;
+ VALUE file;
ID id;
rb_const_flag_t flag;
+ int line;
};
/* always on stack, no need to mark */
@@ -1877,6 +1879,7 @@ autoload_c_compact(void *ptr)
ac->mod = rb_gc_location(ac->mod);
ac->ad = rb_gc_location(ac->ad);
ac->value = rb_gc_location(ac->value);
+ ac->file = rb_gc_location(ac->file);
}
static void
@@ -1887,6 +1890,7 @@ autoload_c_mark(void *ptr)
rb_gc_mark_movable(ac->mod);
rb_gc_mark_movable(ac->ad);
rb_gc_mark_movable(ac->value);
+ rb_gc_mark_movable(ac->file);
}
static void
@@ -2772,11 +2776,11 @@ rb_const_set(VALUE klass, ID id, VALUE val)
setup_const_entry(ce, klass, val, CONST_PUBLIC);
}
else {
- struct autoload_const ac;
- ac.mod = klass;
- ac.id = id;
- ac.value = val;
- ac.flag = CONST_PUBLIC;
+ struct autoload_const ac = {
+ .mod = klass, .id = id,
+ .value = val, .flag = CONST_PUBLIC,
+ /* fill the rest with 0 */
+ };
const_tbl_update(&ac);
}
/*
@@ -2841,10 +2845,17 @@ const_tbl_update(struct autoload_const *ac)
rb_clear_constant_cache();
ac->value = val; /* autoload_i is non-WB-protected */
- return;
+ ac->file = rb_source_location(&ac->line);
}
- /* otherwise, allow to override */
- autoload_delete(klass, id);
+ else {
+ /* otherwise autoloaded constant, allow to override */
+ autoload_delete(klass, id);
+ ce->flag = visibility;
+ RB_OBJ_WRITE(klass, &ce->value, val);
+ RB_OBJ_WRITE(klass, &ce->file, ac->file);
+ ce->line = ac->line;
+ }
+ return;
}
else {
VALUE name = QUOTE_ID(id);