Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/annocheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/baseruby.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/check_dependencies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dependabot_automerge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/modgc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/parse_y.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/spec_guards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/wasm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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' }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/yjit-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/zjit-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 11 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
2 changes: 2 additions & 0 deletions common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions cont.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
}
Expand Down
141 changes: 117 additions & 24 deletions eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion include/ruby/internal/intern/cont.h
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
1 change: 1 addition & 0 deletions internal/eval.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 0 additions & 1 deletion math.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
# define _USE_MATH_DEFINES 1
#endif

#include <errno.h>
#include <float.h>
#include <math.h>

Expand Down
16 changes: 13 additions & 3 deletions spec/ruby/core/fiber/fixtures/classes.rb
Original file line number Diff line number Diff line change
@@ -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

Expand Down
1 change: 1 addition & 0 deletions spec/ruby/core/fiber/raise_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading