From 64f508ade8c8535b7d3ecdd217886aa52fddd43c Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Thu, 24 Jul 2025 14:45:43 +1200 Subject: [PATCH 1/5] Support `cause:` in `Thread#raise` and `Fiber#raise`. (#13967) * Add support for `cause:` argument to `Fiber#raise` and `Thread#raise`. The implementation behaviour is consistent with `Kernel#raise` and `Exception#initialize` methods, allowing the `cause:` argument to be passed to `Fiber#raise` and `Thread#raise`. This change ensures that the `cause:` argument is handled correctly, providing a more consistent and expected behavior when raising exceptions in fibers and threads. [Feature #21360] * Shared specs for Fiber/Thread/Kernel raise. --------- Co-authored-by: Samuel Williams --- NEWS.md | 11 + common.mk | 2 + cont.c | 5 +- eval.c | 141 ++++++++-- include/ruby/internal/intern/cont.h | 2 +- internal/eval.h | 1 + spec/ruby/core/fiber/fixtures/classes.rb | 16 +- spec/ruby/core/fiber/raise_spec.rb | 1 + spec/ruby/core/thread/fixtures/classes.rb | 24 ++ spec/ruby/core/thread/raise_spec.rb | 3 + spec/ruby/shared/kernel/raise.rb | 306 +++++++++++++++++++--- thread.c | 14 +- 12 files changed, 451 insertions(+), 75 deletions(-) diff --git a/NEWS.md b/NEWS.md index 48b9ab421c635b..cf0aaab71448e6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -104,6 +104,16 @@ Note: We're only listing outstanding class updates. * Update Unicode to Version 16.0.0 and Emoji Version 16.0. [[Feature #19908]][[Feature #20724]] (also applies to Regexp) +* Thread + + * Introduce support for `Thread#raise(cause:)` argument similar to + `Kernel#raise`. [[Feature #21360]] + +* Fiber + + * Introduce support for `Fiber#raise(cause:)` argument similar to + `Kernel#raise`. [[Feature #21360]] + * Fiber::Scheduler * Introduce `Fiber::Scheduler#fiber_interrupt` to interrupt a fiber with a @@ -243,3 +253,4 @@ The following bundled gems are updated. [Feature #21262]: https://bugs.ruby-lang.org/issues/21262 [Feature #21287]: https://bugs.ruby-lang.org/issues/21287 [Feature #21347]: https://bugs.ruby-lang.org/issues/21347 +[Feature #21360]: https://bugs.ruby-lang.org/issues/21360 diff --git a/common.mk b/common.mk index 975d4f29bc00ee..896005e76e36b3 100644 --- a/common.mk +++ b/common.mk @@ -4094,6 +4094,7 @@ cont.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h cont.$(OBJEXT): $(top_srcdir)/internal/compilers.h cont.$(OBJEXT): $(top_srcdir)/internal/cont.h cont.$(OBJEXT): $(top_srcdir)/internal/error.h +cont.$(OBJEXT): $(top_srcdir)/internal/eval.h cont.$(OBJEXT): $(top_srcdir)/internal/gc.h cont.$(OBJEXT): $(top_srcdir)/internal/imemo.h cont.$(OBJEXT): $(top_srcdir)/internal/namespace.h @@ -19292,6 +19293,7 @@ thread.$(OBJEXT): $(top_srcdir)/internal/class.h thread.$(OBJEXT): $(top_srcdir)/internal/compilers.h thread.$(OBJEXT): $(top_srcdir)/internal/cont.h thread.$(OBJEXT): $(top_srcdir)/internal/error.h +thread.$(OBJEXT): $(top_srcdir)/internal/eval.h thread.$(OBJEXT): $(top_srcdir)/internal/gc.h thread.$(OBJEXT): $(top_srcdir)/internal/hash.h thread.$(OBJEXT): $(top_srcdir)/internal/imemo.h diff --git a/cont.c b/cont.c index c40ed6715cbfe7..0d7245ed9c20f1 100644 --- a/cont.c +++ b/cont.c @@ -30,6 +30,7 @@ extern int madvise(caddr_t, size_t, int); #include "internal/cont.h" #include "internal/thread.h" #include "internal/error.h" +#include "internal/eval.h" #include "internal/gc.h" #include "internal/proc.h" #include "internal/sanitizers.h" @@ -3218,9 +3219,9 @@ fiber_raise(rb_fiber_t *fiber, VALUE exception) } VALUE -rb_fiber_raise(VALUE fiber, int argc, const VALUE *argv) +rb_fiber_raise(VALUE fiber, int argc, VALUE *argv) { - VALUE exception = rb_make_exception(argc, argv); + VALUE exception = rb_exception_setup(argc, argv); return fiber_raise(fiber_ptr(fiber), exception); } diff --git a/eval.c b/eval.c index 74f31db5c02259..019a2d19a25f3b 100644 --- a/eval.c +++ b/eval.c @@ -703,49 +703,142 @@ rb_interrupt(void) rb_exc_raise(rb_exc_new(rb_eInterrupt, 0, 0)); } -enum {raise_opt_cause, raise_max_opt}; /*< \private */ - static int -extract_raise_opts(int argc, VALUE *argv, VALUE *opts) +extract_raise_options(int argc, VALUE *argv, VALUE *cause) { - int i; + // Keyword arguments: + static ID keywords[1] = {0}; + if (!keywords[0]) { + CONST_ID(keywords[0], "cause"); + } + if (argc > 0) { - VALUE opt; - argc = rb_scan_args(argc, argv, "*:", NULL, &opt); - if (!NIL_P(opt)) { - if (!RHASH_EMPTY_P(opt)) { - ID keywords[1]; - CONST_ID(keywords[0], "cause"); - rb_get_kwargs(opt, keywords, 0, -1-raise_max_opt, opts); - if (!RHASH_EMPTY_P(opt)) argv[argc++] = opt; - return argc; + VALUE options; + argc = rb_scan_args(argc, argv, "*:", NULL, &options); + + if (!NIL_P(options)) { + if (!RHASH_EMPTY_P(options)) { + // Extract optional cause keyword argument, leaving any other options alone: + rb_get_kwargs(options, keywords, 0, -2, cause); + + // If there were any other options, add them back to the arguments: + if (!RHASH_EMPTY_P(options)) argv[argc++] = options; } } } - for (i = 0; i < raise_max_opt; ++i) { - opts[i] = Qundef; - } + return argc; } +/** + * Complete exception setup for cross-context raises (Thread#raise, Fiber#raise). + * Handles keyword extraction, validation, exception creation, and cause assignment. + * + * @param[in] argc Number of arguments + * @param[in] argv Argument array (will be modified for keyword extraction) + * @return Prepared exception object with cause applied + */ +VALUE +rb_exception_setup(int argc, VALUE *argv) +{ + rb_execution_context_t *ec = GET_EC(); + + // Extract cause keyword argument: + VALUE cause = Qundef; + argc = extract_raise_options(argc, argv, &cause); + + // Validate cause-only case: + if (argc == 0 && !UNDEF_P(cause)) { + rb_raise(rb_eArgError, "only cause is given with no arguments"); + } + + // Create exception: + VALUE exception; + if (argc == 0) { + exception = rb_exc_new(rb_eRuntimeError, 0, 0); + } + else { + exception = rb_make_exception(argc, argv); + } + + VALUE resolved_cause = Qnil; + + // Resolve cause with validation: + if (UNDEF_P(cause)) { + // No explicit cause - use automatic cause chaining from calling context: + resolved_cause = rb_ec_get_errinfo(ec); + + // Prevent self-referential cause (e.g. `raise $!`): + if (resolved_cause == exception) { + resolved_cause = Qnil; + } + } + else if (NIL_P(cause)) { + // Explicit nil cause - prevent chaining: + resolved_cause = Qnil; + } + else { + // Explicit cause - validate and assign: + if (!rb_obj_is_kind_of(cause, rb_eException)) { + rb_raise(rb_eTypeError, "exception object expected"); + } + + if (cause == exception) { + // Prevent self-referential cause (e.g. `raise error, cause: error`) - although I'm not sure this is good behaviour, it's inherited from `Kernel#raise`. + resolved_cause = Qnil; + } + else { + // Check for circular causes: + VALUE current_cause = cause; + while (!NIL_P(current_cause)) { + // We guarantee that the cause chain is always terminated. Then, creating an exception with an existing cause is not circular as long as exception is not an existing cause of any other exception. + if (current_cause == exception) { + rb_raise(rb_eArgError, "circular causes"); + } + if (THROW_DATA_P(current_cause)) { + break; + } + current_cause = rb_attr_get(current_cause, id_cause); + } + resolved_cause = cause; + } + } + + // Apply cause to exception object (duplicate if frozen): + if (!UNDEF_P(resolved_cause)) { + if (OBJ_FROZEN(exception)) { + exception = rb_obj_dup(exception); + } + rb_ivar_set(exception, id_cause, resolved_cause); + } + + return exception; +} + VALUE rb_f_raise(int argc, VALUE *argv) { - VALUE err; - VALUE opts[raise_max_opt], *const cause = &opts[raise_opt_cause]; + VALUE cause = Qundef; + argc = extract_raise_options(argc, argv, &cause); - argc = extract_raise_opts(argc, argv, opts); + VALUE exception; + + // Bare re-raise case: if (argc == 0) { - if (!UNDEF_P(*cause)) { + // Cause was extracted, but no arguments were provided: + if (!UNDEF_P(cause)) { rb_raise(rb_eArgError, "only cause is given with no arguments"); } - err = get_errinfo(); - if (!NIL_P(err)) { + + // Otherwise, re-raise the current exception: + exception = get_errinfo(); + if (!NIL_P(exception)) { argc = 1; - argv = &err; + argv = &exception; } } - rb_raise_jump(rb_make_exception(argc, argv), *cause); + + rb_raise_jump(rb_make_exception(argc, argv), cause); UNREACHABLE_RETURN(Qnil); } diff --git a/include/ruby/internal/intern/cont.h b/include/ruby/internal/intern/cont.h index 32647f48aadd0a..e3c89557fda47d 100644 --- a/include/ruby/internal/intern/cont.h +++ b/include/ruby/internal/intern/cont.h @@ -275,7 +275,7 @@ VALUE rb_fiber_transfer_kw(VALUE fiber, int argc, const VALUE *argv, int kw_spla * @exception rb_eFiberError `fiber` is terminated etc. * @return (See rb_fiber_resume() for details) */ -VALUE rb_fiber_raise(VALUE fiber, int argc, const VALUE *argv); +VALUE rb_fiber_raise(VALUE fiber, int argc, VALUE *argv); RBIMPL_SYMBOL_EXPORT_END() diff --git a/internal/eval.h b/internal/eval.h index a8b649e509bc10..4c1c045b4e1042 100644 --- a/internal/eval.h +++ b/internal/eval.h @@ -26,6 +26,7 @@ extern ID ruby_static_id_status; VALUE rb_refinement_module_get_refined_class(VALUE module); void rb_class_modify_check(VALUE); NORETURN(VALUE rb_f_raise(int argc, VALUE *argv)); +VALUE rb_exception_setup(int argc, VALUE *argv); void rb_refinement_setup(struct rb_refinements_data *data, VALUE module, VALUE klass); void rb_vm_using_module(VALUE module); VALUE rb_top_main_class(const char *method); diff --git a/spec/ruby/core/fiber/fixtures/classes.rb b/spec/ruby/core/fiber/fixtures/classes.rb index c00facd6e16c86..6b0e0fbc4261b8 100644 --- a/spec/ruby/core/fiber/fixtures/classes.rb +++ b/spec/ruby/core/fiber/fixtures/classes.rb @@ -1,10 +1,20 @@ module FiberSpecs class NewFiberToRaise - def self.raise(*args) - fiber = Fiber.new { Fiber.yield } + def self.raise(*args, **kwargs, &block) + fiber = Fiber.new do + if block_given? + block.call do + Fiber.yield + end + else + Fiber.yield + end + end + fiber.resume - fiber.raise(*args) + + fiber.raise(*args, **kwargs) end end diff --git a/spec/ruby/core/fiber/raise_spec.rb b/spec/ruby/core/fiber/raise_spec.rb index 124f56fe7da650..896f760290a37b 100644 --- a/spec/ruby/core/fiber/raise_spec.rb +++ b/spec/ruby/core/fiber/raise_spec.rb @@ -4,6 +4,7 @@ describe "Fiber#raise" do it_behaves_like :kernel_raise, :raise, FiberSpecs::NewFiberToRaise + it_behaves_like :kernel_raise_across_contexts, :raise, FiberSpecs::NewFiberToRaise end describe "Fiber#raise" do diff --git a/spec/ruby/core/thread/fixtures/classes.rb b/spec/ruby/core/thread/fixtures/classes.rb index 23a090feb0d0c1..54bd85fae30b6e 100644 --- a/spec/ruby/core/thread/fixtures/classes.rb +++ b/spec/ruby/core/thread/fixtures/classes.rb @@ -6,6 +6,30 @@ def initialize(*args) end end + class NewThreadToRaise + def self.raise(*args, **kwargs, &block) + thread = Thread.new do + Thread.current.report_on_exception = false + + if block_given? + block.call do + sleep + end + else + sleep + end + end + + Thread.pass until thread.stop? + + thread.raise(*args, **kwargs) + + thread.join + ensure + thread.kill if thread.alive? + end + end + class Status attr_reader :thread, :inspect, :status, :to_s def initialize(thread) diff --git a/spec/ruby/core/thread/raise_spec.rb b/spec/ruby/core/thread/raise_spec.rb index 49323cf2705a7a..b473eabd42c492 100644 --- a/spec/ruby/core/thread/raise_spec.rb +++ b/spec/ruby/core/thread/raise_spec.rb @@ -3,6 +3,9 @@ require_relative '../../shared/kernel/raise' describe "Thread#raise" do + it_behaves_like :kernel_raise, :raise, ThreadSpecs::NewThreadToRaise + it_behaves_like :kernel_raise_across_contexts, :raise, ThreadSpecs::NewThreadToRaise + it "ignores dead threads and returns nil" do t = Thread.new { :dead } Thread.pass while t.alive? diff --git a/spec/ruby/shared/kernel/raise.rb b/spec/ruby/shared/kernel/raise.rb index 3d1c4a10f5807b..d46c4b7b15f07e 100644 --- a/spec/ruby/shared/kernel/raise.rb +++ b/spec/ruby/shared/kernel/raise.rb @@ -104,43 +104,24 @@ def e.exception end it "re-raises a previously rescued exception without overwriting the backtrace" do - # This spec is written using #backtrace and matching the line number - # from the string, as backtrace_locations is a more advanced - # method that is not always supported by implementations. - # - initial_raise_line = nil - raise_again_line = nil - raised_again = nil - - if defined?(FiberSpecs::NewFiberToRaise) and @object == FiberSpecs::NewFiberToRaise - fiber = Fiber.new do - begin - initial_raise_line = __LINE__; Fiber.yield - rescue => raised - begin - raise_again_line = __LINE__; Fiber.yield raised - rescue => raised_again - raised_again - end - end - end - fiber.resume - raised = fiber.raise 'raised' - raised_again = fiber.raise raised - else - begin - initial_raise_line = __LINE__; @object.raise 'raised' - rescue => raised - begin - raise_again_line = __LINE__; @object.raise raised - rescue => raised_again - raised_again - end - end + exception = nil + + begin + raise "raised" + rescue => exception + # Ignore. + end + + backtrace = exception.backtrace + + begin + raised_exception = @object.raise(exception) + rescue => raised_exception + # Ignore. end - raised_again.backtrace.first.should include("#{__FILE__}:#{initial_raise_line}:") - raised_again.backtrace.first.should_not include("#{__FILE__}:#{raise_again_line}:") + raised_exception.backtrace.should == backtrace + raised_exception.should == exception end it "allows Exception, message, and backtrace parameters" do @@ -159,4 +140,259 @@ def e.exception } end end + + ruby_version_is "3.5" do + it "allows cause keyword argument" do + cause = StandardError.new("original error") + result = nil + + -> do + @object.raise("new error", cause: cause) + end.should raise_error(RuntimeError, "new error") do |error| + error.cause.should == cause + end + end + + it "raises an ArgumentError when only cause is given" do + cause = StandardError.new("cause") + -> do + @object.raise(cause: cause) + end.should raise_error(ArgumentError, "only cause is given with no arguments") + end + + it "raises an ArgumentError when only cause is given and is nil" do + -> do + @object.raise(cause: nil) + end.should raise_error(ArgumentError, "only cause is given with no arguments") + end + + it "raises a TypeError when given cause is not an instance of Exception" do + cause = Object.new + -> do + @object.raise("message", cause: cause) + end.should raise_error(TypeError, "exception object expected") + end + + it "doesn't set given cause when it equals the raised exception" do + cause = StandardError.new("cause") + result = nil + + -> do + @object.raise(cause, cause: cause) + end.should raise_error(StandardError, "cause") do |error| + error.should == cause + error.cause.should == nil + end + end + + it "accepts cause equal an exception" do + error = RuntimeError.new("message") + result = nil + + -> do + @object.raise(error, cause: error) + end.should raise_error(RuntimeError, "message") do |error| + error.cause.should == nil + end + end + + it "rejects circular causes" do + -> { + begin + raise "Error 1" + rescue => error1 + begin + raise "Error 2" + rescue => error2 + begin + raise "Error 3" + rescue => error3 + @object.raise(error1, cause: error3) + end + end + end + }.should raise_error(ArgumentError, "circular causes") + end + + it "supports exception class with message and cause" do + cause = StandardError.new("cause message") + result = nil + + -> do + @object.raise(ArgumentError, "argument error message", cause: cause) + end.should raise_error(ArgumentError, "argument error message") do |error| + error.should be_kind_of(ArgumentError) + error.message.should == "argument error message" + error.cause.should == cause + end + end + + it "supports exception class with message, backtrace and cause" do + cause = StandardError.new("cause message") + backtrace = ["line1", "line2"] + result = nil + + -> do + @object.raise(ArgumentError, "argument error message", backtrace, cause: cause) + end.should raise_error(ArgumentError, "argument error message") do |error| + error.should be_kind_of(ArgumentError) + error.message.should == "argument error message" + error.cause.should == cause + error.backtrace.should == backtrace + end + end + + it "supports automatic cause chaining" do + -> do + begin + raise "first error" + rescue + # No explicit cause - should chain automatically: + @object.raise("second error") + end + end.should raise_error(RuntimeError, "second error") do |error| + error.cause.should be_kind_of(RuntimeError) + error.cause.message.should == "first error" + end + end + + it "supports cause: nil to prevent automatic cause chaining" do + -> do + begin + raise "first error" + rescue + # Explicit nil prevents chaining: + @object.raise("second error", cause: nil) + end + end.should raise_error(RuntimeError, "second error") do |error| + error.cause.should == nil + end + end + end +end + +describe :kernel_raise_across_contexts, shared: true do + ruby_version_is "3.5" do + describe "with cause keyword argument" do + it "uses the cause from the calling context" do + original_cause = nil + result = nil + + # We have no cause ($!) and we don't specify one explicitly either: + @object.raise("second error") do |&block| + begin + begin + raise "first error" + rescue => original_cause + # We have a cause here ($!) but we should ignore it: + block.call + end + rescue => result + # Ignore. + end + end + + result.should be_kind_of(RuntimeError) + result.message.should == "second error" + result.cause.should == nil + end + + it "accepts a cause keyword argument that overrides the last exception" do + original_cause = nil + override_cause = StandardError.new("override cause") + result = nil + + begin + raise "outer error" + rescue + # We have an existing cause, but we want to override it: + @object.raise("second error", cause: override_cause) do |&block| + begin + begin + raise "first error" + rescue => original_cause + # We also have an existing cause here: + block.call + end + rescue => result + # Ignore. + end + end + end + + result.should be_kind_of(RuntimeError) + result.message.should == "second error" + result.cause.should == override_cause + end + + it "supports automatic cause chaining from calling context" do + result = nil + + @object.raise("new error") do |&block| + begin + begin + raise "original error" + rescue + block.call # Let the context yield/sleep + end + rescue => result + # Ignore. + end + end + + result.should be_kind_of(RuntimeError) + result.message.should == "new error" + # Calling context has no current exception: + result.cause.should == nil + end + + it "supports explicit cause: nil to prevent cause chaining" do + result = nil + + begin + raise "calling context error" + rescue + @object.raise("new error", cause: nil) do |&block| + begin + begin + raise "target context error" + rescue + block.call # Let the context yield/sleep + end + rescue => result + # Ignore. + end + end + + result.should be_kind_of(RuntimeError) + result.message.should == "new error" + result.cause.should == nil + end + end + + it "raises TypeError when cause is not an Exception" do + -> { + @object.raise("error", cause: "not an exception") do |&block| + begin + block.call # Let the context yield/sleep + rescue + # Ignore - we expect the TypeError to be raised in the calling context + end + end + }.should raise_error(TypeError, "exception object expected") + end + + it "raises ArgumentError when only cause is given with no arguments" do + -> { + @object.raise(cause: StandardError.new("cause")) do |&block| + begin + block.call # Let the context yield/sleep + rescue + # Ignore - we expect the ArgumentError to be raised in the calling context + end + end + }.should raise_error(ArgumentError, "only cause is given with no arguments") + end + end + end end diff --git a/thread.c b/thread.c index 6eb16beed65acc..97e9561f3af3c5 100644 --- a/thread.c +++ b/thread.c @@ -78,6 +78,7 @@ #include "internal/class.h" #include "internal/cont.h" #include "internal/error.h" +#include "internal/eval.h" #include "internal/gc.h" #include "internal/hash.h" #include "internal/io.h" @@ -2710,18 +2711,11 @@ rb_threadptr_ready(rb_thread_t *th) static VALUE rb_threadptr_raise(rb_thread_t *target_th, int argc, VALUE *argv) { - VALUE exc; - if (rb_threadptr_dead(target_th)) { return Qnil; } - if (argc == 0) { - exc = rb_exc_new(rb_eRuntimeError, 0, 0); - } - else { - exc = rb_make_exception(argc, argv); - } + VALUE exception = rb_exception_setup(argc, argv); /* making an exception object can switch thread, so we need to check thread deadness again */ @@ -2729,9 +2723,9 @@ rb_threadptr_raise(rb_thread_t *target_th, int argc, VALUE *argv) return Qnil; } - rb_ec_setup_exception(GET_EC(), exc, Qundef); - rb_threadptr_pending_interrupt_enque(target_th, exc); + rb_threadptr_pending_interrupt_enque(target_th, exception); rb_threadptr_interrupt(target_th); + return Qnil; } From 076e51e5ec5924554ab5c1eca483a52405d0fdc4 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 23 Jul 2025 08:07:19 +0000 Subject: [PATCH 2/5] math.c: cleanup unused `#include ` `errno` is no longer used after 5073155a178a9f478950afef4f148e44fd14b5d6 --- math.c | 1 - 1 file changed, 1 deletion(-) diff --git a/math.c b/math.c index 2394fe9f588a4a..a95919e3420e8e 100644 --- a/math.c +++ b/math.c @@ -15,7 +15,6 @@ # define _USE_MATH_DEFINES 1 #endif -#include #include #include From 6dc37f9003bed2ea58792f859a6a2f6edea8bc32 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 24 Jul 2025 10:14:14 +0900 Subject: [PATCH 3/5] Update the latest versions of actions --- .github/workflows/annocheck.yml | 2 +- .github/workflows/baseruby.yml | 2 +- .github/workflows/check_dependencies.yml | 2 +- .github/workflows/dependabot_automerge.yml | 2 +- .github/workflows/modgc.yml | 2 +- .github/workflows/parse_y.yml | 2 +- .github/workflows/spec_guards.yml | 2 +- .github/workflows/ubuntu.yml | 2 +- .github/workflows/wasm.yml | 2 +- .github/workflows/windows.yml | 2 +- .github/workflows/yjit-ubuntu.yml | 2 +- .github/workflows/zjit-ubuntu.yml | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/annocheck.yml b/.github/workflows/annocheck.yml index a890fc442f09fb..be85205feed097 100644 --- a/.github/workflows/annocheck.yml +++ b/.github/workflows/annocheck.yml @@ -74,7 +74,7 @@ jobs: builddir: build makeup: true - - uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0 + - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0 with: ruby-version: '3.1' bundler: none diff --git a/.github/workflows/baseruby.yml b/.github/workflows/baseruby.yml index 8b77b0188934f9..87162936fd8ff5 100644 --- a/.github/workflows/baseruby.yml +++ b/.github/workflows/baseruby.yml @@ -50,7 +50,7 @@ jobs: - ruby-3.3 steps: - - uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0 + - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0 with: ruby-version: ${{ matrix.ruby }} bundler: none diff --git a/.github/workflows/check_dependencies.yml b/.github/workflows/check_dependencies.yml index 22452a3b9e822e..6d85cf8e9c043a 100644 --- a/.github/workflows/check_dependencies.yml +++ b/.github/workflows/check_dependencies.yml @@ -40,7 +40,7 @@ jobs: - uses: ./.github/actions/setup/directories - - uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0 + - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0 with: ruby-version: '3.1' bundler: none diff --git a/.github/workflows/dependabot_automerge.yml b/.github/workflows/dependabot_automerge.yml index 09fdba7b2b66af..2d2427a907fc12 100644 --- a/.github/workflows/dependabot_automerge.yml +++ b/.github/workflows/dependabot_automerge.yml @@ -17,7 +17,7 @@ jobs: id: metadata - name: Wait for status checks - uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc # v1.3.4 + uses: lewagon/wait-on-check-action@31f07a800aa1ba8518509dc8561cdf5a891deb4b # v1.4.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} ref: ${{ github.event.pull_request.head.sha || github.sha }} diff --git a/.github/workflows/modgc.yml b/.github/workflows/modgc.yml index 815994b395b08e..fe10979a5fc9d3 100644 --- a/.github/workflows/modgc.yml +++ b/.github/workflows/modgc.yml @@ -63,7 +63,7 @@ jobs: uses: ./.github/actions/setup/ubuntu if: ${{ contains(matrix.os, 'ubuntu') }} - - uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0 + - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0 with: ruby-version: '3.1' bundler: none diff --git a/.github/workflows/parse_y.yml b/.github/workflows/parse_y.yml index eb7c6c22026530..9345a1f7a465fc 100644 --- a/.github/workflows/parse_y.yml +++ b/.github/workflows/parse_y.yml @@ -60,7 +60,7 @@ jobs: - uses: ./.github/actions/setup/ubuntu - - uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0 + - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0 with: ruby-version: '3.1' bundler: none diff --git a/.github/workflows/spec_guards.yml b/.github/workflows/spec_guards.yml index d723abde21ab69..34b0202e9fb6da 100644 --- a/.github/workflows/spec_guards.yml +++ b/.github/workflows/spec_guards.yml @@ -48,7 +48,7 @@ jobs: steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0 + - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0 with: ruby-version: ${{ matrix.ruby }} bundler: none diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 3005809b08c475..fa271e5cb57c61 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -68,7 +68,7 @@ jobs: with: arch: ${{ matrix.arch }} - - uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0 + - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0 with: ruby-version: '3.1' bundler: none diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 2c49d990719637..9294e2d339bf4c 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -100,7 +100,7 @@ jobs: run: | echo "WASI_SDK_PATH=/opt/wasi-sdk" >> $GITHUB_ENV - - uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0 + - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0 with: ruby-version: '3.1' bundler: none diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 47e3f53241eafb..28adf526c7d0d8 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -61,7 +61,7 @@ jobs: - run: md build working-directory: - - uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0 + - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0 with: # windows-11-arm has only 3.4.1, 3.4.2, 3.4.3, head ruby-version: ${{ !endsWith(matrix.os, 'arm') && '3.1' || '3.4' }} diff --git a/.github/workflows/yjit-ubuntu.yml b/.github/workflows/yjit-ubuntu.yml index d71c5df48a51b8..7ec4de8cdce66b 100644 --- a/.github/workflows/yjit-ubuntu.yml +++ b/.github/workflows/yjit-ubuntu.yml @@ -135,7 +135,7 @@ jobs: - uses: ./.github/actions/setup/ubuntu - - uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0 + - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0 with: ruby-version: '3.1' bundler: none diff --git a/.github/workflows/zjit-ubuntu.yml b/.github/workflows/zjit-ubuntu.yml index c16535c507c9b5..09fa137f45a571 100644 --- a/.github/workflows/zjit-ubuntu.yml +++ b/.github/workflows/zjit-ubuntu.yml @@ -77,7 +77,7 @@ jobs: - uses: ./.github/actions/setup/ubuntu - - uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0 + - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0 with: ruby-version: '3.1' bundler: none From b246fb604e9674922cde6353c657b61f61ccb743 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Thu, 24 Jul 2025 12:56:08 +0900 Subject: [PATCH 4/5] Use `<>` for a system header --- time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/time.c b/time.c index 1eb8f8da9c9a3a..4c2b15d90e227d 100644 --- a/time.c +++ b/time.c @@ -46,7 +46,7 @@ #include "timev.h" #if defined(_WIN32) -# include "timezoneapi.h" /* DYNAMIC_TIME_ZONE_INFORMATION */ +# include /* DYNAMIC_TIME_ZONE_INFORMATION */ #endif #include "builtin.h" From 4c60e431e1fd8d196807c9d42cc0355cd339e1fc Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Thu, 24 Jul 2025 15:42:55 +0900 Subject: [PATCH 5/5] Win32: Suppress an error message when baseruby is not found --- win32/Makefile.sub | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/win32/Makefile.sub b/win32/Makefile.sub index 7c125a4a02ecc6..48289702cd1f11 100644 --- a/win32/Makefile.sub +++ b/win32/Makefile.sub @@ -23,10 +23,10 @@ MFLAGS=-l # executable in $(tooldir). ! if [cd $(tooldir) && ruby missing-baseruby.bat 2> nul] ! else if [(cd $(tooldir) && for %I in (ruby.exe) do @echo BASERUBY = %~s$$PATH:I) > baseruby.mk] -! else +! else if exist(baseruby.mk) ! include baseruby.mk ! endif -! if [del baseruby.mk] +! if [del baseruby.mk 2> nul] ! endif !else if "$(BASERUBY)" == "no" || [($(BASERUBY) -eexit) > nul 2> nul] BASERUBY =