diff --git a/.github/workflows/zjit-macos.yml b/.github/workflows/zjit-macos.yml index d5ada785b16ecf..9a32771be53a1c 100644 --- a/.github/workflows/zjit-macos.yml +++ b/.github/workflows/zjit-macos.yml @@ -93,7 +93,7 @@ jobs: rustup install ${{ matrix.rust_version }} --profile minimal rustup default ${{ matrix.rust_version }} - - uses: taiki-e/install-action@bfadeaba214680fb4ab63e710bcb2a6a17019fdc # v2.70.4 + - uses: taiki-e/install-action@0cccd59f03b32c54f0db097c518c320bfc8c73b3 # v2.71.1 with: tool: nextest@0.9 if: ${{ matrix.test_task == 'zjit-check' }} diff --git a/.github/workflows/zjit-ubuntu.yml b/.github/workflows/zjit-ubuntu.yml index fc34cc2202aab5..40f5d100b7fd16 100644 --- a/.github/workflows/zjit-ubuntu.yml +++ b/.github/workflows/zjit-ubuntu.yml @@ -119,7 +119,7 @@ jobs: ruby-version: '3.1' bundler: none - - uses: taiki-e/install-action@bfadeaba214680fb4ab63e710bcb2a6a17019fdc # v2.70.4 + - uses: taiki-e/install-action@0cccd59f03b32c54f0db097c518c320bfc8c73b3 # v2.71.1 with: tool: nextest@0.9 if: ${{ matrix.test_task == 'zjit-check' }} diff --git a/compile.c b/compile.c index 910e9a8b63ea92..5decd5e59e742d 100644 --- a/compile.c +++ b/compile.c @@ -6090,6 +6090,23 @@ compile_const_prefix(rb_iseq_t *iseq, const NODE *const node, return COMPILE_OK; } +static int +cpath_const_p(const NODE *node) +{ + switch (nd_type(node)) { + case NODE_CONST: + case NODE_COLON3: + return TRUE; + case NODE_COLON2: + if (RNODE_COLON2(node)->nd_head) { + return cpath_const_p(RNODE_COLON2(node)->nd_head); + } + return TRUE; + default: + return FALSE; + } +} + static int compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath) { @@ -6099,9 +6116,13 @@ compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath) return VM_DEFINECLASS_FLAG_SCOPED; } else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) { - /* Bar::Foo */ + /* Bar::Foo or expr::Foo */ NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head)); - return VM_DEFINECLASS_FLAG_SCOPED; + int flags = VM_DEFINECLASS_FLAG_SCOPED; + if (!cpath_const_p(RNODE_COLON2(cpath)->nd_head)) { + flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF; + } + return flags; } else { /* class at cbase Foo */ @@ -11477,9 +11498,20 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv)); ADD_INSN (ret, node, putnil); CONST_ID(singletonclass, "singletonclass"); + + /* `class << self` in a class body and `class << Foo` (constant + receiver) are stable. All other forms are potentially dynamic. */ + int sclass_flags = VM_DEFINECLASS_TYPE_SINGLETON_CLASS; + const NODE *recv = RNODE_SCLASS(node)->nd_recv; + if (!(nd_type_p(recv, NODE_SELF) && + ISEQ_BODY(iseq)->type == ISEQ_TYPE_CLASS) && + !cpath_const_p(recv)) { + sclass_flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF; + } + ADD_INSN3(ret, node, defineclass, ID2SYM(singletonclass), singleton_class, - INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS)); + INT2FIX(sclass_flags)); RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class); if (popped) { diff --git a/eval_intern.h b/eval_intern.h index 91808f1f29aa43..2090fbfcab96cf 100644 --- a/eval_intern.h +++ b/eval_intern.h @@ -172,9 +172,10 @@ rb_ec_tag_jump(const rb_execution_context_t *ec, enum ruby_tag_type st) /* CREF operators */ -#define CREF_FL_PUSHED_BY_EVAL IMEMO_FL_USER1 -#define CREF_FL_OMOD_SHARED IMEMO_FL_USER2 -#define CREF_FL_SINGLETON IMEMO_FL_USER3 +#define CREF_FL_PUSHED_BY_EVAL IMEMO_FL_USER1 +#define CREF_FL_OMOD_SHARED IMEMO_FL_USER2 +#define CREF_FL_SINGLETON IMEMO_FL_USER3 +#define CREF_FL_DYNAMIC_CREF IMEMO_FL_USER4 static inline int CREF_SINGLETON(const rb_cref_t *cref); @@ -260,6 +261,18 @@ CREF_OMOD_SHARED_SET(rb_cref_t *cref) cref->flags |= CREF_FL_OMOD_SHARED; } +static inline int +CREF_DYNAMIC(const rb_cref_t *cref) +{ + return cref->flags & CREF_FL_DYNAMIC_CREF; +} + +static inline void +CREF_DYNAMIC_SET(rb_cref_t *cref) +{ + cref->flags |= CREF_FL_DYNAMIC_CREF; +} + static inline void CREF_OMOD_SHARED_UNSET(rb_cref_t *cref) { diff --git a/insns.def b/insns.def index df4147efdeacf8..9705b33e64027f 100644 --- a/insns.def +++ b/insns.def @@ -811,10 +811,16 @@ defineclass rb_iseq_check(class_iseq); + rb_cref_t *cref = vm_cref_push(ec, klass, NULL, FALSE, FALSE); + + if (VM_DEFINECLASS_DYNAMIC_CREF_P(flags)) { + CREF_DYNAMIC_SET(cref); + } + /* enter scope */ vm_push_frame(ec, class_iseq, VM_FRAME_MAGIC_CLASS | VM_ENV_FLAG_LOCAL, klass, GC_GUARDED_PTR(box), - (VALUE)vm_cref_push(ec, klass, NULL, FALSE, FALSE), + (VALUE)cref, ISEQ_BODY(class_iseq)->iseq_encoded, GET_SP(), ISEQ_BODY(class_iseq)->local_table_size, ISEQ_BODY(class_iseq)->stack_max); diff --git a/lib/bundler/stub_specification.rb b/lib/bundler/stub_specification.rb index 026f753d411fd8..b353642b4062fe 100644 --- a/lib/bundler/stub_specification.rb +++ b/lib/bundler/stub_specification.rb @@ -52,6 +52,7 @@ def manually_installed? # This is defined directly to avoid having to loading the full spec def missing_extensions? + return false if RUBY_ENGINE == "jruby" return false if default_gem? return false if extensions.empty? return false if File.exist? gem_build_complete_path diff --git a/lib/rubygems/commands/pristine_command.rb b/lib/rubygems/commands/pristine_command.rb index 942b75fba172d3..10978c2af7cf93 100644 --- a/lib/rubygems/commands/pristine_command.rb +++ b/lib/rubygems/commands/pristine_command.rb @@ -132,6 +132,11 @@ def execute specs = specs.select {|spec| spec.platform == RUBY_ENGINE || Gem::Platform.local === spec.platform || spec.platform == Gem::Platform::RUBY } if specs.to_a.empty? + if options[:only_missing_extensions] + say "No gems with missing extensions to restore" + return + end + raise Gem::Exception, "Failed to find gems #{options[:args]} #{options[:version]}" end diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb index 235ccdb458f1d4..89aa84a1c7339c 100644 --- a/lib/rubygems/package.rb +++ b/lib/rubygems/package.rb @@ -556,6 +556,15 @@ def open_tar_gz(io) # :nodoc: tar = Gem::Package::TarReader.new gzio yield tar + ensure + # Consume remaining gzip data to prevent the + # "attempt to close unfinished zstream; reset forced" warning + # when the GzipReader is closed with unconsumed compressed data. + begin + IO.copy_stream(gzio, IO::NULL) + rescue Zlib::GzipFile::Error, IOError + nil + end end end diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index cf96348620262c..51729d755be367 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -2070,6 +2070,7 @@ def method_missing(sym, *a, &b) # :nodoc: # probably want to build_extensions def missing_extensions? + return false if RUBY_ENGINE == "jruby" return false if extensions.empty? return false if default_gem? return false if File.exist? gem_build_complete_path diff --git a/lib/rubygems/stub_specification.rb b/lib/rubygems/stub_specification.rb index 4f6a70ba4b4b81..53b337ed8554cb 100644 --- a/lib/rubygems/stub_specification.rb +++ b/lib/rubygems/stub_specification.rb @@ -140,6 +140,7 @@ def raw_require_paths # :nodoc: end def missing_extensions? + return false if RUBY_ENGINE == "jruby" return false if default_gem? return false if extensions.empty? return false if File.exist? gem_build_complete_path diff --git a/prism_compile.c b/prism_compile.c index d30785bb883dc2..4f22baaad5c97e 100644 --- a/prism_compile.c +++ b/prism_compile.c @@ -1377,6 +1377,23 @@ pm_new_child_iseq(rb_iseq_t *iseq, pm_scope_node_t *node, VALUE name, const rb_i return ret_iseq; } +static int +pm_cpath_const_p(const pm_node_t *node) +{ + switch (PM_NODE_TYPE(node)) { + case PM_CONSTANT_READ_NODE: + return TRUE; + case PM_CONSTANT_PATH_NODE: + { + const pm_node_t *parent = ((const pm_constant_path_node_t *) node)->parent; + if (!parent) return TRUE; /* ::Foo */ + return pm_cpath_const_p(parent); + } + default: + return FALSE; + } +} + static int pm_compile_class_path(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) { @@ -1384,9 +1401,13 @@ pm_compile_class_path(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_loca const pm_node_t *parent = ((const pm_constant_path_node_t *) node)->parent; if (parent) { - /* Bar::Foo */ + /* Bar::Foo or expr::Foo */ PM_COMPILE(parent); - return VM_DEFINECLASS_FLAG_SCOPED; + int flags = VM_DEFINECLASS_FLAG_SCOPED; + if (!pm_cpath_const_p(parent)) { + flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF; + } + return flags; } else { /* toplevel class ::Foo */ @@ -10342,7 +10363,17 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, ID singletonclass; CONST_ID(singletonclass, "singletonclass"); - PUSH_INSN3(ret, location, defineclass, ID2SYM(singletonclass), child_iseq, INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS)); + + /* `class << self` in a class body and `class << Foo` (constant + receiver) are stable. All other forms are potentially dynamic. */ + int sclass_flags = VM_DEFINECLASS_TYPE_SINGLETON_CLASS; + if (!(PM_NODE_TYPE_P(cast->expression, PM_SELF_NODE) && + ISEQ_BODY(iseq)->type == ISEQ_TYPE_CLASS) && + !pm_cpath_const_p(cast->expression)) { + sclass_flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF; + } + + PUSH_INSN3(ret, location, defineclass, ID2SYM(singletonclass), child_iseq, INT2FIX(sclass_flags)); if (popped) PUSH_INSN(ret, location, pop); RB_OBJ_WRITTEN(iseq, Qundef, (VALUE) child_iseq); diff --git a/spec/bundler/bundler/stub_specification_spec.rb b/spec/bundler/bundler/stub_specification_spec.rb index beb966b3ce8b56..f2faa2ea641953 100644 --- a/spec/bundler/bundler/stub_specification_spec.rb +++ b/spec/bundler/bundler/stub_specification_spec.rb @@ -49,10 +49,14 @@ expect(stub.missing_extensions?).to be false end - it "returns true if not manually_installed?" do + it "returns #{RUBY_ENGINE == "jruby" ? "false" : "true"} if not manually_installed?" do stub = described_class.from_stub(with_bundler_stub_spec) stub.installed_by_version = Gem::Version.new(1) - expect(stub.missing_extensions?).to be true + if RUBY_ENGINE == "jruby" + expect(stub.missing_extensions?).to be false + else + expect(stub.missing_extensions?).to be true + end end end diff --git a/spec/bundler/install/gemfile/git_spec.rb b/spec/bundler/install/gemfile/git_spec.rb index 05081a8bce46a0..9baf0464c8440c 100644 --- a/spec/bundler/install/gemfile/git_spec.rb +++ b/spec/bundler/install/gemfile/git_spec.rb @@ -1404,7 +1404,7 @@ File.open(git_reader.path.join("ext/foo.c"), "w") do |file| file.write <<-C #include "ruby.h" - VALUE foo() { return INT2FIX(#{i}); } + VALUE foo(VALUE self) { return INT2FIX(#{i}); } void Init_foo() { rb_define_global_function("foo", &foo, 0); } C end diff --git a/test/ruby/test_class.rb b/test/ruby/test_class.rb index 61182b990b3abf..8e3f3933b08a0d 100644 --- a/test/ruby/test_class.rb +++ b/test/ruby/test_class.rb @@ -733,6 +733,29 @@ def xyzzy } end + def test_dynamic_module_cpath_constant_namespace # [Bug #20948] + assert_separately([], <<~'RUBY') + module M1 + module Foo + X = 1 + end + end + + module M2 + module Foo + X = 2 + end + end + + results = [M1, M2].map do + module it::Foo + X + end + end + assert_equal([1, 2], results) + RUBY + end + def test_namescope_error_message m = Module.new o = m.module_eval "class A\u{3042}; self; end.new" diff --git a/test/ruby/test_variable.rb b/test/ruby/test_variable.rb index 13b8a7905f2b46..f3484fddce5783 100644 --- a/test/ruby/test_variable.rb +++ b/test/ruby/test_variable.rb @@ -120,6 +120,34 @@ class Parent TestVariable.send(:remove_const, :Parent) rescue nil end + def test_cvar_cache_invalidated_by_parent_class_variable_set + m = Module.new { class_variable_set(:@@x, 1) } + a = Class.new + b = Class.new(a) do + include m + class_eval "def self.x; @@x; end" + end + assert_equal 1, b.x # warm cache + a.class_variable_set(:@@x, 2) + error = assert_raise(RuntimeError) { b.x } + assert_match(/class variable @@x of .+ is overtaken by .+/, error.message) + end + + def test_cvar_cache_invalidated_by_module_class_variable_set + m = Module.new + n = Module.new + b = Class.new do + include m + include n + class_eval "def self.x; @@x; end" + end + m.class_variable_set(:@@x, 1) + assert_equal 1, b.x # warm cache + n.class_variable_set(:@@x, 2) + error = assert_raise(RuntimeError) { b.x } + assert_match(/class variable @@x of .+ is overtaken by .+/, error.message) + end + def test_cvar_overtaken_by_module error = eval <<~EORB class ParentForModule diff --git a/test/ruby/test_yjit.rb b/test/ruby/test_yjit.rb index 87782a65e9ae0d..721d070399d1e4 100644 --- a/test/ruby/test_yjit.rb +++ b/test/ruby/test_yjit.rb @@ -547,7 +547,7 @@ def get_foo end def test_opt_getconstant_path_slowpath - assert_compiles(<<~RUBY, exits: { opt_getconstant_path: 1 }, result: [42, 42, 1, 1], call_threshold: 2) + assert_compiles(<<~RUBY, result: [42, 42, 1, 1], call_threshold: 2) class A FOO = 42 class << self diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb index de475d0891fd3f..f3d9ef95d69d02 100644 --- a/test/rubygems/test_gem.rb +++ b/test/rubygems/test_gem.rb @@ -1304,10 +1304,14 @@ def test_self_try_activate_missing_extensions refute Gem.try_activate "nonexistent" end - expected = "Ignoring ext-1 because its extensions are not built. " \ - "Try: gem pristine ext --version 1\n" + if RUBY_ENGINE == "jruby" + assert_equal "", err + else + expected = "Ignoring ext-1 because its extensions are not built. " \ + "Try: gem pristine ext --version 1\n" - assert_equal expected, err + assert_equal expected, err + end end def test_self_use_paths_with_nils diff --git a/test/rubygems/test_gem_commands_pristine_command.rb b/test/rubygems/test_gem_commands_pristine_command.rb index e9c4d329450f88..0ea140897ce1f2 100644 --- a/test/rubygems/test_gem_commands_pristine_command.rb +++ b/test/rubygems/test_gem_commands_pristine_command.rb @@ -248,7 +248,13 @@ def test_execute_extensions_only_missing_extensions end refute_includes @ui.output, "Restored #{a.full_name}" - assert_includes @ui.output, "Restored #{b.full_name}" + + if Gem.java_platform? + refute_includes @ui.output, "Restored #{b.full_name}" + assert_includes @ui.output, "No gems with missing extensions to restore" + else + assert_includes @ui.output, "Restored #{b.full_name}" + end end def test_execute_no_extension diff --git a/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock b/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock index d7638709b5d491..f96e796794e4fa 100644 --- a/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock +++ b/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock @@ -13,16 +13,14 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.69.1" +version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ffcebc3849946a7170a05992aac39da343a90676ab392c51a4280981d6379c2" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ "bitflags", "cexpr", "clang-sys", - "lazy_static", - "lazycell", - "peeking_take_while", + "itertools", "proc-macro2", "quote", "regex", @@ -70,6 +68,12 @@ dependencies = [ "rb-sys", ] +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + [[package]] name = "glob" version = "0.3.0" @@ -77,16 +81,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] -name = "lazy_static" -version = "1.4.0" +name = "itertools" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] [[package]] -name = "lazycell" -version = "1.3.0" +name = "lazy_static" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" @@ -126,17 +133,11 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -152,18 +153,18 @@ dependencies = [ [[package]] name = "rb-sys" -version = "0.9.124" +version = "0.9.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85c4188462601e2aa1469def389c17228566f82ea72f137ed096f21591bc489" +checksum = "85b37650fabd8ba515910a0dc089dcb6348eb3c35fbf91698cb226435be2babc" dependencies = [ "rb-sys-build", ] [[package]] name = "rb-sys-build" -version = "0.9.124" +version = "0.9.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "568068db4102230882e6d4ae8de6632e224ca75fe5970f6e026a04e91ed635d3" +checksum = "c73b806faa66006e491458b48a78725621c1ac5a2a6efe2614c90711a7780b80" dependencies = [ "bindgen", "lazy_static", @@ -193,9 +194,9 @@ checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" [[package]] name = "rustc-hash" -version = "1.1.0" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" [[package]] name = "shell-words" diff --git a/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml b/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml index 223b8abd47c2d2..e9e21e0f4f8aba 100644 --- a/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml +++ b/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml @@ -7,4 +7,4 @@ edition = "2021" crate-type = ["cdylib"] [dependencies] -rb-sys = "0.9.124" +rb-sys = "0.9.125" diff --git a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock index 6c41c44c45e403..358d0f5a41fc45 100644 --- a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock +++ b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock @@ -13,16 +13,14 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.69.1" +version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ffcebc3849946a7170a05992aac39da343a90676ab392c51a4280981d6379c2" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ "bitflags", "cexpr", "clang-sys", - "lazy_static", - "lazycell", - "peeking_take_while", + "itertools", "proc-macro2", "quote", "regex", @@ -63,6 +61,12 @@ dependencies = [ "libloading", ] +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + [[package]] name = "glob" version = "0.3.0" @@ -70,16 +74,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] -name = "lazy_static" -version = "1.4.0" +name = "itertools" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] [[package]] -name = "lazycell" -version = "1.3.0" +name = "lazy_static" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" @@ -119,17 +126,11 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -145,18 +146,18 @@ dependencies = [ [[package]] name = "rb-sys" -version = "0.9.124" +version = "0.9.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85c4188462601e2aa1469def389c17228566f82ea72f137ed096f21591bc489" +checksum = "85b37650fabd8ba515910a0dc089dcb6348eb3c35fbf91698cb226435be2babc" dependencies = [ "rb-sys-build", ] [[package]] name = "rb-sys-build" -version = "0.9.124" +version = "0.9.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "568068db4102230882e6d4ae8de6632e224ca75fe5970f6e026a04e91ed635d3" +checksum = "c73b806faa66006e491458b48a78725621c1ac5a2a6efe2614c90711a7780b80" dependencies = [ "bindgen", "lazy_static", @@ -193,9 +194,9 @@ dependencies = [ [[package]] name = "rustc-hash" -version = "1.1.0" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" [[package]] name = "shell-words" diff --git a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml index f1699f2b16e3e2..f9583c0e337c66 100644 --- a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml +++ b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml @@ -7,4 +7,4 @@ edition = "2021" crate-type = ["cdylib"] [dependencies] -rb-sys = "0.9.124" +rb-sys = "0.9.125" diff --git a/test/rubygems/test_gem_specification.rb b/test/rubygems/test_gem_specification.rb index 4d9661396f4030..52ae9773131b0c 100644 --- a/test/rubygems/test_gem_specification.rb +++ b/test/rubygems/test_gem_specification.rb @@ -1578,13 +1578,21 @@ def test_contains_requirable_file_eh_extension ext_spec _, err = capture_output do - refute @ext.contains_requirable_file? "nonexistent" + if RUBY_ENGINE == "jruby" + refute @ext.ignored? + else + refute @ext.contains_requirable_file? "nonexistent" + end end - expected = "Ignoring ext-1 because its extensions are not built. " \ - "Try: gem pristine ext --version 1\n" + if RUBY_ENGINE == "jruby" + assert_equal "", err + else + expected = "Ignoring ext-1 because its extensions are not built. " \ + "Try: gem pristine ext --version 1\n" - assert_equal expected, err + assert_equal expected, err + end end def test_contains_requirable_file_eh_extension_java_platform @@ -4007,7 +4015,11 @@ def test_metadata_specs def test_missing_extensions_eh ext_spec - assert @ext.missing_extensions? + if RUBY_ENGINE == "jruby" + refute @ext.missing_extensions? + else + assert @ext.missing_extensions? + end extconf_rb = File.join @ext.gem_dir, @ext.extensions.first FileUtils.mkdir_p File.dirname extconf_rb diff --git a/test/rubygems/test_gem_stub_specification.rb b/test/rubygems/test_gem_stub_specification.rb index 4b2d4c570a137b..f04b36dbf86cfd 100644 --- a/test/rubygems/test_gem_stub_specification.rb +++ b/test/rubygems/test_gem_stub_specification.rb @@ -68,13 +68,21 @@ def test_contains_requirable_file_eh def test_contains_requirable_file_eh_extension stub_with_extension do |stub| _, err = capture_output do - refute stub.contains_requirable_file? "nonexistent" + if RUBY_ENGINE == "jruby" + refute stub.ignored? + else + refute stub.contains_requirable_file? "nonexistent" + end end - expected = "Ignoring stub_e-2 because its extensions are not built. " \ - "Try: gem pristine stub_e --version 2\n" + if RUBY_ENGINE == "jruby" + assert_equal "", err + else + expected = "Ignoring stub_e-2 because its extensions are not built. " \ + "Try: gem pristine stub_e --version 2\n" - assert_equal expected, err + assert_equal expected, err + end end end @@ -137,7 +145,11 @@ def test_missing_extensions_eh end end - assert stub.missing_extensions? + if RUBY_ENGINE == "jruby" + refute stub.missing_extensions? + else + assert stub.missing_extensions? + end stub.build_extensions diff --git a/test/socket/test_socket.rb b/test/socket/test_socket.rb index 0d5bad96920890..3b5f5b9d74c979 100644 --- a/test/socket/test_socket.rb +++ b/test/socket/test_socket.rb @@ -548,7 +548,8 @@ def test_bintime timestamp_retry_rw(s1, :BINTIME) } t = stamp.timestamp - assert_equal(stamp.data.unpack1("Q", offset: -8), t.subsec * 2**64) + data = stamp.data + assert_equal(data.unpack1("Q", offset: data.bytesize-8), t.subsec * 2**64) end def test_closed_read diff --git a/variable.c b/variable.c index 3ae06b069b732c..9df6e5911cfca1 100644 --- a/variable.c +++ b/variable.c @@ -4246,20 +4246,6 @@ find_cvar(VALUE klass, VALUE * front, VALUE * target, ID id) return v; } -static void -check_for_cvar_table(VALUE subclass, VALUE key) -{ - if (RB_TYPE_P(subclass, T_ICLASS)) return; // skip refinement ICLASSes - - if (RTEST(rb_ivar_defined(subclass, key))) { - RB_DEBUG_COUNTER_INC(cvar_class_invalidate); - ruby_vm_global_cvar_state++; - return; - } - - rb_class_foreach_subclass(subclass, check_for_cvar_table, key); -} - void rb_cvar_set(VALUE klass, ID id, VALUE val) { @@ -4306,15 +4292,11 @@ rb_cvar_set(VALUE klass, ID id, VALUE val) ent->global_cvar_state = GET_GLOBAL_CVAR_STATE(); } - // Break the cvar cache if this is a new class variable - // and target is a module or a subclass with the same - // cvar in this lookup. + // Break the cvar cache if this is a new class variable. + // Existing caches may have resolved this name to a different + // location in the hierarchy, so we must invalidate globally. if (new_cvar) { - if (RB_TYPE_P(target, T_CLASS)) { - if (RCLASS_SUBCLASSES_FIRST(target)) { - rb_class_foreach_subclass(target, check_for_cvar_table, id); - } - } + ruby_vm_global_cvar_state++; } } diff --git a/vm_core.h b/vm_core.h index 85664e18b8396b..a0044ccc852da4 100644 --- a/vm_core.h +++ b/vm_core.h @@ -1243,9 +1243,12 @@ typedef enum { #define VM_DEFINECLASS_TYPE(x) ((rb_vm_defineclass_type_t)(x) & VM_DEFINECLASS_TYPE_MASK) #define VM_DEFINECLASS_FLAG_SCOPED 0x08 #define VM_DEFINECLASS_FLAG_HAS_SUPERCLASS 0x10 +#define VM_DEFINECLASS_FLAG_DYNAMIC_CREF 0x20 #define VM_DEFINECLASS_SCOPED_P(x) ((x) & VM_DEFINECLASS_FLAG_SCOPED) #define VM_DEFINECLASS_HAS_SUPERCLASS_P(x) \ ((x) & VM_DEFINECLASS_FLAG_HAS_SUPERCLASS) +#define VM_DEFINECLASS_DYNAMIC_CREF_P(x) \ + ((x) & VM_DEFINECLASS_FLAG_DYNAMIC_CREF) /* iseq.c */ RUBY_SYMBOL_EXPORT_BEGIN diff --git a/vm_insnhelper.c b/vm_insnhelper.c index e3f627ae896cff..705199ea1fd4c3 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -989,14 +989,14 @@ vm_get_const_key_cref(const VALUE *ep) const rb_cref_t *key_cref = cref; while (cref) { - if (RCLASS_SINGLETON_P(CREF_CLASS(cref)) || - RCLASS_CLONED_P(CREF_CLASS(cref)) ) { + if (CREF_DYNAMIC(cref) || + RCLASS_CLONED_P(CREF_CLASS(cref))) { return key_cref; } cref = CREF_NEXT(cref); } - /* does not include singleton class */ + /* no dynamic singleton class or cloned class found */ return NULL; }