Preserve ensure handlers for unreachable labels

Ensure catch entries must remain active when dead code removal leaves
unplaced range labels.  Dropping them skips ensure clauses on exceptions.

See https://github.com/ruby/ruby/pull/19513#issuecomment-6460531535.
This commit is contained in:
Nobuyoshi Nakada 2026-10-28 15:29:32 +09:00
parent e80cd771b3
commit b1f8ac364d
No known key found for this signature in database
GPG Key ID: 3582D74E1FEE4465
Notes: git 2026-10-28 07:16:01 +00:00
2 changed files with 19 additions and 1 deletions

View File

@ -3118,7 +3118,11 @@ iseq_set_exception_table(rb_iseq_t *iseq)
int end = label_get_position((LABEL *)(ptr[2] & ~1));
int cont = 0;
int sp = 0;
if (start < 0 || end < 0) continue;
if (start < 0 || end < 0) {
if ((ptr[0] & 0xffff) != CATCH_TYPE_ENSURE) continue;
if (start < 0) start = 0;
if (end < 0) end = 0;
}
if (ptr[4]) {
LABEL *lobj = (LABEL *)(ptr[4] & ~1);
cont = label_get_position(lobj);

View File

@ -933,6 +933,20 @@ class TestISeq < Test::Unit::TestCase
RUBY
end
def test_short_circuited_return_in_ensure
assert_in_out_err(["--parser=parse.y"], <<~'RUBY', ["ensure", "#<RuntimeError: boom>"], success: true)
def m
begin
if false && (return if foo); end
raise 'boom'
ensure
puts 'ensure'
end
end
m rescue p $!
RUBY
end
def test_unreachable_syntax_error
mesg = /Invalid break/
assert_syntax_error("false and break", mesg)