Skip to content

Commit 47c97e1

Browse files
committed
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 ruby#11055]
1 parent b96d559 commit 47c97e1

File tree

2 files changed

+69
-0
lines changed

2 files changed

+69
-0
lines changed

test/ruby/test_autoload.rb

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,66 @@ class AutoloadTest
295295
end
296296
end
297297

298+
def test_autoload_private_constant_before_autoload
299+
Dir.mktmpdir('autoload') do |tmpdir|
300+
File.write(tmpdir+"/zzz.rb", "#{<<~"begin;"}\n#{<<~'end;'}")
301+
begin;
302+
class AutoloadTest
303+
ZZZ = :ZZZ
304+
end
305+
end;
306+
assert_separately(%W[-I #{tmpdir}], "#{<<-"begin;"}\n#{<<-'end;'}")
307+
bug = '[Bug #11055]'
308+
begin;
309+
class AutoloadTest
310+
autoload :ZZZ, "zzz.rb"
311+
private_constant :ZZZ
312+
ZZZ
313+
end
314+
assert_raise(NameError, bug) {AutoloadTest::ZZZ}
315+
end;
316+
assert_separately(%W[-I #{tmpdir}], "#{<<-"begin;"}\n#{<<-'end;'}")
317+
bug = '[Bug #11055]'
318+
begin;
319+
class AutoloadTest
320+
autoload :ZZZ, "zzz.rb"
321+
private_constant :ZZZ
322+
end
323+
assert_raise(NameError, bug) {AutoloadTest::ZZZ}
324+
end;
325+
end
326+
end
327+
328+
def test_autoload_deprecate_constant_before_autoload
329+
Dir.mktmpdir('autoload') do |tmpdir|
330+
File.write(tmpdir+"/zzz.rb", "#{<<~"begin;"}\n#{<<~'end;'}")
331+
begin;
332+
class AutoloadTest
333+
ZZZ = :ZZZ
334+
end
335+
end;
336+
assert_separately(%W[-I #{tmpdir}], "#{<<-"begin;"}\n#{<<-'end;'}")
337+
bug = '[Bug #11055]'
338+
begin;
339+
class AutoloadTest
340+
autoload :ZZZ, "zzz.rb"
341+
deprecate_constant :ZZZ
342+
end
343+
assert_warning(/ZZZ is deprecated/, bug) {class AutoloadTest; ZZZ; end}
344+
assert_warning(/ZZZ is deprecated/, bug) {AutoloadTest::ZZZ}
345+
end;
346+
assert_separately(%W[-I #{tmpdir}], "#{<<-"begin;"}\n#{<<-'end;'}")
347+
bug = '[Bug #11055]'
348+
begin;
349+
class AutoloadTest
350+
autoload :ZZZ, "zzz.rb"
351+
deprecate_constant :ZZZ
352+
end
353+
assert_warning(/ZZZ is deprecated/, bug) {AutoloadTest::ZZZ}
354+
end;
355+
end
356+
end
357+
298358
def test_autoload_fork
299359
EnvUtil.default_warning do
300360
Tempfile.create(['autoload', '.rb']) {|file|

variable.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2226,13 +2226,19 @@ rb_autoload_load(VALUE mod, ID id)
22262226
struct autoload_data_i *ele;
22272227
struct autoload_const *ac;
22282228
struct autoload_state state;
2229+
int flag = -1;
2230+
rb_const_entry_t *ce;
22292231

22302232
if (!autoload_defined_p(mod, id)) return Qfalse;
22312233
load = check_autoload_required(mod, id, &loading);
22322234
if (!load) return Qfalse;
22332235
src = rb_sourcefile();
22342236
if (src && loading && strcmp(src, loading) == 0) return Qfalse;
22352237

2238+
if ((ce = rb_const_lookup(mod, id))) {
2239+
flag = ce->flag & (CONST_DEPRECATED | CONST_VISIBILITY_MASK);
2240+
}
2241+
22362242
/* set ele->state for a marker of autoloading thread */
22372243
if (!(ele = get_autoload_data(load, &ac))) {
22382244
return Qfalse;
@@ -2264,6 +2270,9 @@ rb_autoload_load(VALUE mod, ID id)
22642270
result = rb_ensure(autoload_require, (VALUE)&state,
22652271
autoload_reset, (VALUE)&state);
22662272

2273+
if (flag > 0 && (ce = rb_const_lookup(mod, id))) {
2274+
ce->flag |= flag;
2275+
}
22672276
RB_GC_GUARD(load);
22682277
return result;
22692278
}

0 commit comments

Comments
 (0)