Use rb_error_frozen_object in rb_class_modify_check

This provides information on the class of the frozen object. It also
results in a much simpler implementation.

Fixes [Bug #21374]
This commit is contained in:
Jeremy Evans 2025-11-22 19:58:43 -08:00
parent 76fb0d244b
commit e436dba9fe
Notes: git 2025-12-09 22:36:21 +00:00
5 changed files with 14 additions and 39 deletions

32
eval.c
View File

@ -428,40 +428,10 @@ rb_class_modify_check(VALUE klass)
rb_class_set_initialized(klass);
}
if (OBJ_FROZEN(klass)) {
const char *desc;
if (RCLASS_SINGLETON_P(klass)) {
desc = "object";
klass = RCLASS_ATTACHED_OBJECT(klass);
if (!SPECIAL_CONST_P(klass)) {
switch (BUILTIN_TYPE(klass)) {
case T_MODULE:
case T_ICLASS:
desc = "Module";
break;
case T_CLASS:
desc = "Class";
break;
default:
break;
}
}
}
else {
switch (BUILTIN_TYPE(klass)) {
case T_MODULE:
case T_ICLASS:
desc = "module";
break;
case T_CLASS:
desc = "class";
break;
default:
Check_Type(klass, T_CLASS);
UNREACHABLE;
}
}
rb_frozen_error_raise(klass, "can't modify frozen %s: %"PRIsVALUE, desc, klass);
rb_error_frozen_object(klass);
}
}

View File

@ -26,9 +26,11 @@ describe "FrozenError#message" do
object = Object.new
object.freeze
msg_class = RUBY_VERSION >= "4" ? "Object" : "object"
-> {
def object.x; end
}.should raise_error(FrozenError, "can't modify frozen object: #{object}")
}.should raise_error(FrozenError, "can't modify frozen #{msg_class}: #{object}")
object = [].freeze
-> { object << nil }.should raise_error(FrozenError, "can't modify frozen Array: []")

View File

@ -97,7 +97,8 @@ describe "An instance method" do
def foo; end
end
}.should raise_error(FrozenError) { |e|
e.message.should == "can't modify frozen module: #{e.receiver}"
msg_class = RUBY_VERSION >= "4" ? "Module" : "module"
e.message.should == "can't modify frozen #{msg_class}: #{e.receiver}"
}
-> {
@ -106,7 +107,8 @@ describe "An instance method" do
def foo; end
end
}.should raise_error(FrozenError){ |e|
e.message.should == "can't modify frozen class: #{e.receiver}"
msg_class = RUBY_VERSION >= "4" ? "Class" : "class"
e.message.should == "can't modify frozen #{msg_class}: #{e.receiver}"
}
end
end
@ -283,7 +285,8 @@ describe "A singleton method definition" do
it "raises FrozenError with the correct class name" do
obj = Object.new
obj.freeze
-> { def obj.foo; end }.should raise_error(FrozenError, "can't modify frozen object: #{obj}")
msg_class = RUBY_VERSION >= "4" ? "Object" : "object"
-> { def obj.foo; end }.should raise_error(FrozenError, "can't modify frozen #{msg_class}: #{obj}")
obj = Object.new
c = obj.singleton_class

View File

@ -601,7 +601,7 @@ class TestClass < Test::Unit::TestCase
obj = Object.new
c = obj.singleton_class
obj.freeze
assert_raise_with_message(FrozenError, /frozen object/) {
assert_raise_with_message(FrozenError, /frozen Object/) {
c.class_eval {def f; end}
}
end

View File

@ -3016,17 +3016,17 @@ class TestModule < Test::Unit::TestCase
bug11532 = '[ruby-core:70828] [Bug #11532]'
c = Class.new {const_set(:A, 1)}.freeze
assert_raise_with_message(FrozenError, /frozen class/, bug11532) {
assert_raise_with_message(FrozenError, /frozen Class/, bug11532) {
c.class_eval {private_constant :A}
}
c = Class.new {const_set(:A, 1); private_constant :A}.freeze
assert_raise_with_message(FrozenError, /frozen class/, bug11532) {
assert_raise_with_message(FrozenError, /frozen Class/, bug11532) {
c.class_eval {public_constant :A}
}
c = Class.new {const_set(:A, 1)}.freeze
assert_raise_with_message(FrozenError, /frozen class/, bug11532) {
assert_raise_with_message(FrozenError, /frozen Class/, bug11532) {
c.class_eval {deprecate_constant :A}
}
end