ruby-changes:59056
From: Jeremy <ko1@a...>
Date: Wed, 4 Dec 2019 00:32:06 +0900 (JST)
Subject: [ruby-changes:59056] 47c97e1e84 (master): Do not lose existing constant visibility when autoloading
https://git.ruby-lang.org/ruby.git/commit/?id=47c97e1e84 From 47c97e1e843159c3c4d57f8c5e22daea57c3ffe1 Mon Sep 17 00:00:00 2001 From: Jeremy Evans <code@j...> Date: Sun, 11 Aug 2019 20:53:37 -0700 Subject: Do not lose existing constant visibility when autoloading This copies the private/deprecate constant visibility across the autoload. It still is backwards compatible with setting the private/deprecate constant visibility in the autoloaded file. However, if you explicitly set public constant in the autoloaded file, that will be reset after the autoload. Fixes [Bug #11055] diff --git a/test/ruby/test_autoload.rb b/test/ruby/test_autoload.rb index 53510e8..e9e13ee 100644 --- a/test/ruby/test_autoload.rb +++ b/test/ruby/test_autoload.rb @@ -295,6 +295,66 @@ p Foo::Bar https://github.com/ruby/ruby/blob/trunk/test/ruby/test_autoload.rb#L295 end end + def test_autoload_private_constant_before_autoload + Dir.mktmpdir('autoload') do |tmpdir| + File.write(tmpdir+"/zzz.rb", "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + class AutoloadTest + ZZZ = :ZZZ + end + end; + assert_separately(%W[-I #{tmpdir}], "#{<<-"begin;"}\n#{<<-'end;'}") + bug = '[Bug #11055]' + begin; + class AutoloadTest + autoload :ZZZ, "zzz.rb" + private_constant :ZZZ + ZZZ + end + assert_raise(NameError, bug) {AutoloadTest::ZZZ} + end; + assert_separately(%W[-I #{tmpdir}], "#{<<-"begin;"}\n#{<<-'end;'}") + bug = '[Bug #11055]' + begin; + class AutoloadTest + autoload :ZZZ, "zzz.rb" + private_constant :ZZZ + end + assert_raise(NameError, bug) {AutoloadTest::ZZZ} + end; + end + end + + def test_autoload_deprecate_constant_before_autoload + Dir.mktmpdir('autoload') do |tmpdir| + File.write(tmpdir+"/zzz.rb", "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + class AutoloadTest + ZZZ = :ZZZ + end + end; + assert_separately(%W[-I #{tmpdir}], "#{<<-"begin;"}\n#{<<-'end;'}") + bug = '[Bug #11055]' + begin; + class AutoloadTest + autoload :ZZZ, "zzz.rb" + deprecate_constant :ZZZ + end + assert_warning(/ZZZ is deprecated/, bug) {class AutoloadTest; ZZZ; end} + assert_warning(/ZZZ is deprecated/, bug) {AutoloadTest::ZZZ} + end; + assert_separately(%W[-I #{tmpdir}], "#{<<-"begin;"}\n#{<<-'end;'}") + bug = '[Bug #11055]' + begin; + class AutoloadTest + autoload :ZZZ, "zzz.rb" + deprecate_constant :ZZZ + end + assert_warning(/ZZZ is deprecated/, bug) {AutoloadTest::ZZZ} + end; + end + end + def test_autoload_fork EnvUtil.default_warning do Tempfile.create(['autoload', '.rb']) {|file| diff --git a/variable.c b/variable.c index 9c50b75..74c4472 100644 --- a/variable.c +++ b/variable.c @@ -2226,6 +2226,8 @@ rb_autoload_load(VALUE mod, ID id) https://github.com/ruby/ruby/blob/trunk/variable.c#L2226 struct autoload_data_i *ele; struct autoload_const *ac; struct autoload_state state; + int flag = -1; + rb_const_entry_t *ce; if (!autoload_defined_p(mod, id)) return Qfalse; load = check_autoload_required(mod, id, &loading); @@ -2233,6 +2235,10 @@ rb_autoload_load(VALUE mod, ID id) https://github.com/ruby/ruby/blob/trunk/variable.c#L2235 src = rb_sourcefile(); if (src && loading && strcmp(src, loading) == 0) return Qfalse; + if ((ce = rb_const_lookup(mod, id))) { + flag = ce->flag & (CONST_DEPRECATED | CONST_VISIBILITY_MASK); + } + /* set ele->state for a marker of autoloading thread */ if (!(ele = get_autoload_data(load, &ac))) { return Qfalse; @@ -2264,6 +2270,9 @@ rb_autoload_load(VALUE mod, ID id) https://github.com/ruby/ruby/blob/trunk/variable.c#L2270 result = rb_ensure(autoload_require, (VALUE)&state, autoload_reset, (VALUE)&state); + if (flag > 0 && (ce = rb_const_lookup(mod, id))) { + ce->flag |= flag; + } RB_GC_GUARD(load); return result; } -- cgit v0.10.2 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/