diff options
author | Luke Gruber <[email protected]> | 2024-09-29 12:39:23 -0400 |
---|---|---|
committer | Nobuyoshi Nakada <[email protected]> | 2024-10-01 02:12:56 +0900 |
commit | d592ddd5e619ffe1691b8050de2ccc3e1bd6e080 (patch) | |
tree | 01102e6ea49ef52cf3c8ad4c5d1124d8ec088efc /test | |
parent | 2a58092360c70caf7544544c95549b4c83e81237 (diff) |
Fix compile issue with a short-circuited if/unless condition and `defined?`
This caused an issue when `defined?` was in the `if` condition. Its
instructions weren't appended to the instruction sequence even though it was compiled
if a compile-time known logical short-circuit happened before the `defined?`. The catch table
entry (`defined?` compilation produces a catch table entry) was still on the iseq even though the
instructions weren't there. This caused faulty exception handling in the method.
The solution is to no add the catch table entry for `defined?` after a compile-time known logical
short circuit.
This shouldn't touch much code, it's only for cases like the following,
which can occur during debugging:
if false && defined?(Some::CONSTANT)
"more code..."
end
Fixes [Bug #20501]
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/11554
Diffstat (limited to 'test')
-rw-r--r-- | test/ruby/test_syntax.rb | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb index 3ea6932b9c..08b4a7ee1c 100644 --- a/test/ruby/test_syntax.rb +++ b/test/ruby/test_syntax.rb @@ -2229,6 +2229,43 @@ eom RUBY end + def test_defined_in_short_circuit_if_condition + bug = '[ruby-core:20501]' + conds = [ + "false && defined?(Some::CONSTANT)", + "true || defined?(Some::CONSTANT)", + "(false && defined?(Some::CONSTANT))", # parens exercise different code path + "(true || defined?(Some::CONSTANT))", + "@val && false && defined?(Some::CONSTANT)", + "@val || true || defined?(Some::CONSTANT)" + ] + + conds.each do |cond| + code = %Q{ + def my_method + var = nil + if #{cond} + "here" + end + raise + end + begin + my_method + rescue + print 'ok' + else + print 'ng' + end + } + # Invoke in a subprocess because the bug caused a segfault using the parse.y compiler. + # Don't use assert_separately because the bug was best reproducible in a clean slate, + # without test env loaded. + out, _err, status = EnvUtil.invoke_ruby(["--disable-gems"], code, true, false) + assert_predicate(status, :success?, bug) + assert_equal 'ok', out + end + end + private def not_label(x) @result = x; @not_label ||= nil end |