From 188af773e56abe12932eb456959bef6d02bccd46 Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@jeremyevans.net>
Date: Mon, 27 Nov 2017 21:00:54 -0800
Subject: [PATCH] Add FrozenError as a subclass of RuntimeError

FrozenError will be used instead of RuntimeError for exceptions
raised when there is an attempt to modify a frozen object. The
reason for this change is to differentiate exceptions related
to frozen objects from generic exceptions such as those generated
by Kernel#raise without an exception class.
---
 error.c                                 | 19 ++++++++++++------
 include/ruby/ruby.h                     |  1 +
 object.c                                |  2 +-
 test/-ext-/string/test_enc_associate.rb |  4 ++--
 test/date/test_date_marshal.rb          |  4 ++--
 test/dbm/test_dbm.rb                    |  2 +-
 test/gdbm/test_gdbm.rb                  |  2 +-
 test/pathname/test_pathname.rb          |  2 +-
 test/ruby/test_array.rb                 | 26 ++++++++++++-------------
 test/ruby/test_class.rb                 |  4 ++--
 test/ruby/test_enumerator.rb            |  4 ++--
 test/ruby/test_eval.rb                  |  2 +-
 test/ruby/test_hash.rb                  |  4 ++--
 test/ruby/test_lazy_enumerator.rb       |  2 +-
 test/ruby/test_literal.rb               |  2 +-
 test/ruby/test_marshal.rb               |  2 +-
 test/ruby/test_module.rb                | 18 ++++++++---------
 test/ruby/test_object.rb                | 12 ++++++------
 test/ruby/test_pack.rb                  |  2 +-
 test/ruby/test_rand.rb                  |  4 ++--
 test/ruby/test_range.rb                 |  2 +-
 test/ruby/test_rubyoptions.rb           |  2 +-
 test/ruby/test_string.rb                | 34 ++++++++++++++++-----------------
 test/ruby/test_thread.rb                |  4 ++--
 test/ruby/test_transcode.rb             |  4 ++--
 test/ruby/test_variable.rb              |  4 ++--
 test/stringio/test_stringio.rb          |  6 +++---
 test/test_delegate.rb                   |  4 ++--
 test/test_set.rb                        |  8 ++++----
 29 files changed, 97 insertions(+), 89 deletions(-)

diff --git a/error.c b/error.c
index f00951940f..d257028ad2 100644
--- a/error.c
+++ b/error.c
@@ -804,6 +804,7 @@ VALUE rb_eSignal;
 VALUE rb_eFatal;
 VALUE rb_eStandardError;
 VALUE rb_eRuntimeError;
+VALUE rb_eFrozenError;
 VALUE rb_eTypeError;
 VALUE rb_eArgError;
 VALUE rb_eIndexError;
@@ -2011,16 +2012,21 @@ syserr_eqq(VALUE self, VALUE exc)
  */
 
 /*
- *  Document-class: RuntimeError
+ *  Document-class: FrozenError
  *
- *  A generic error class raised when an invalid operation is attempted.
+ *  Raised when there is an attempt to modify a frozen object.
  *
  *     [1, 2, 3].freeze << 4
  *
  *  <em>raises the exception:</em>
  *
- *     RuntimeError: can't modify frozen Array
+ *     FrozenError: can't modify frozen Array
+ */
+
+/*
+ *  Document-class: RuntimeError
  *
+ *  A generic error class raised when an invalid operation is attempted.
  *  Kernel#raise will raise a RuntimeError if no Exception class is
  *  specified.
  *
@@ -2233,6 +2239,7 @@ Init_Exception(void)
     rb_define_method(rb_eNoMethodError, "private_call?", nometh_err_private_call_p, 0);
 
     rb_eRuntimeError = rb_define_class("RuntimeError", rb_eStandardError);
+    rb_eFrozenError = rb_define_class("FrozenError", rb_eRuntimeError);
     rb_eSecurityError = rb_define_class("SecurityError", rb_eException);
     rb_eNoMemError = rb_define_class("NoMemoryError", rb_eException);
     rb_eEncodingError = rb_define_class("EncodingError", rb_eStandardError);
@@ -2588,7 +2595,7 @@ rb_load_fail(VALUE path, const char *err)
 void
 rb_error_frozen(const char *what)
 {
-    rb_raise(rb_eRuntimeError, "can't modify frozen %s", what);
+    rb_raise(rb_eFrozenError, "can't modify frozen %s", what);
 }
 
 void
@@ -2601,11 +2608,11 @@ rb_error_frozen_object(VALUE frozen_obj)
 	VALUE path = rb_ary_entry(debug_info, 0);
 	VALUE line = rb_ary_entry(debug_info, 1);
 
-	rb_raise(rb_eRuntimeError, "can't modify frozen %"PRIsVALUE", created at %"PRIsVALUE":%"PRIsVALUE,
+	rb_raise(rb_eFrozenError, "can't modify frozen %"PRIsVALUE", created at %"PRIsVALUE":%"PRIsVALUE,
 		 CLASS_OF(frozen_obj), path, line);
     }
     else {
-	rb_raise(rb_eRuntimeError, "can't modify frozen %"PRIsVALUE,
+	rb_raise(rb_eFrozenError, "can't modify frozen %"PRIsVALUE,
 		 CLASS_OF(frozen_obj));
     }
 }
diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h
index ac0cecd952..809ea5460e 100644
--- a/include/ruby/ruby.h
+++ b/include/ruby/ruby.h
@@ -1946,6 +1946,7 @@ RUBY_EXTERN VALUE rb_eKeyError;
 RUBY_EXTERN VALUE rb_eRangeError;
 RUBY_EXTERN VALUE rb_eIOError;
 RUBY_EXTERN VALUE rb_eRuntimeError;
+RUBY_EXTERN VALUE rb_eFrozenError;
 RUBY_EXTERN VALUE rb_eSecurityError;
 RUBY_EXTERN VALUE rb_eSystemCallError;
 RUBY_EXTERN VALUE rb_eThreadError;
diff --git a/object.c b/object.c
index ba43eaf70c..86050da967 100644
--- a/object.c
+++ b/object.c
@@ -1315,7 +1315,7 @@ rb_obj_infect(VALUE victim, VALUE carrier)
  *
  *  <em>produces:</em>
  *
- *     prog.rb:3:in `<<': can't modify frozen Array (RuntimeError)
+ *     prog.rb:3:in `<<': can't modify frozen Array (FrozenError)
  *     	from prog.rb:3
  *
  *  Objects of the following classes are always frozen: Integer,
diff --git a/test/-ext-/string/test_enc_associate.rb b/test/-ext-/string/test_enc_associate.rb
index 4fad8e1cc8..95d1f00cd2 100644
--- a/test/-ext-/string/test_enc_associate.rb
+++ b/test/-ext-/string/test_enc_associate.rb
@@ -7,8 +7,8 @@ def test_frozen
     s = Bug::String.new("abc")
     s.force_encoding(Encoding::US_ASCII)
     s.freeze
-    assert_raise(RuntimeError) {s.associate_encoding!(Encoding::US_ASCII)}
-    assert_raise(RuntimeError) {s.associate_encoding!(Encoding::UTF_8)}
+    assert_raise(FrozenError) {s.associate_encoding!(Encoding::US_ASCII)}
+    assert_raise(FrozenError) {s.associate_encoding!(Encoding::UTF_8)}
   end
 
   Encoding.list.select(&:dummy?).each do |enc|
diff --git a/test/date/test_date_marshal.rb b/test/date/test_date_marshal.rb
index 10e396b71b..99a7239f95 100644
--- a/test/date/test_date_marshal.rb
+++ b/test/date/test_date_marshal.rb
@@ -30,13 +30,13 @@ def test_marshal
     a = d.marshal_dump
     d.freeze
     assert(d.frozen?)
-    assert_raise(RuntimeError){d.marshal_load(a)}
+    assert_raise(FrozenError){d.marshal_load(a)}
 
     d = DateTime.now
     a = d.marshal_dump
     d.freeze
     assert(d.frozen?)
-    assert_raise(RuntimeError){d.marshal_load(a)}
+    assert_raise(FrozenError){d.marshal_load(a)}
   end
 
 end
diff --git a/test/dbm/test_dbm.rb b/test/dbm/test_dbm.rb
index 0812b4023f..93198fdea2 100644
--- a/test/dbm/test_dbm.rb
+++ b/test/dbm/test_dbm.rb
@@ -625,7 +625,7 @@ def test_newdb_open
     def test_freeze
       DBM.open("#{@tmproot}/a") {|d|
         d.freeze
-        assert_raise(RuntimeError) { d["k"] = "v" }
+        assert_raise(FrozenError) { d["k"] = "v" }
       }
     end
   end
diff --git a/test/gdbm/test_gdbm.rb b/test/gdbm/test_gdbm.rb
index 9a9dc28972..1d69634f88 100644
--- a/test/gdbm/test_gdbm.rb
+++ b/test/gdbm/test_gdbm.rb
@@ -722,7 +722,7 @@ def test_newdb_open
     def test_freeze
       GDBM.open("#{@tmproot}/a.dbm") {|d|
         d.freeze
-        assert_raise(RuntimeError) { d["k"] = "v" }
+        assert_raise(FrozenError) { d["k"] = "v" }
       }
     end
   end
diff --git a/test/pathname/test_pathname.rb b/test/pathname/test_pathname.rb
index 5007ebac22..ad104d06df 100644
--- a/test/pathname/test_pathname.rb
+++ b/test/pathname/test_pathname.rb
@@ -635,7 +635,7 @@ def test_freeze_and_taint
     obj = Pathname.new("a")
     obj.freeze
     assert_equal(false, obj.tainted?)
-    assert_raise(RuntimeError) { obj.taint }
+    assert_raise(FrozenError) { obj.taint }
 
     obj = Pathname.new("a")
     obj.taint
diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb
index 508312e4a2..7e63623b7d 100644
--- a/test/ruby/test_array.rb
+++ b/test/ruby/test_array.rb
@@ -601,7 +601,7 @@ def test_concat
     assert_equal([4, 5, 4, 5, 4, 5], b)
 
     assert_raise(TypeError) { [0].concat(:foo) }
-    assert_raise(RuntimeError) { [0].freeze.concat(:foo) }
+    assert_raise(FrozenError) { [0].freeze.concat(:foo) }
   end
 
   def test_count
@@ -1299,10 +1299,10 @@ def test_replace
 
     fa = a.dup.freeze
     assert_nothing_raised(RuntimeError) { a.replace(a) }
-    assert_raise(RuntimeError) { fa.replace(fa) }
+    assert_raise(FrozenError) { fa.replace(fa) }
     assert_raise(ArgumentError) { fa.replace() }
     assert_raise(TypeError) { a.replace(42) }
-    assert_raise(RuntimeError) { fa.replace(42) }
+    assert_raise(FrozenError) { fa.replace(42) }
   end
 
   def test_reverse
@@ -1530,7 +1530,7 @@ def test_sort_bang_with_freeze
     o2 = o1.clone
     ary << o1 << o2
     orig = ary.dup
-    assert_raise(RuntimeError, "frozen during comparison") {ary.sort!}
+    assert_raise(FrozenError, "frozen during comparison") {ary.sort!}
     assert_equal(orig, ary, "must not be modified once frozen")
   end
 
@@ -1762,7 +1762,7 @@ def test_uniq!
     f = a.dup.freeze
     assert_raise(ArgumentError) { a.uniq!(1) }
     assert_raise(ArgumentError) { f.uniq!(1) }
-    assert_raise(RuntimeError) { f.uniq! }
+    assert_raise(FrozenError) { f.uniq! }
 
     assert_nothing_raised do
       a = [ {c: "b"}, {c: "r"}, {c: "w"}, {c: "g"}, {c: "g"} ]
@@ -1808,7 +1808,7 @@ def test_uniq_bang_with_block
   def test_uniq_bang_with_freeze
     ary = [1,2]
     orig = ary.dup
-    assert_raise(RuntimeError, "frozen during comparison") {
+    assert_raise(FrozenError, "frozen during comparison") {
       ary.uniq! {|v| ary.freeze; 1}
     }
     assert_equal(orig, ary, "must not be modified once frozen")
@@ -2121,7 +2121,7 @@ def test_aset_error
     assert_raise(ArgumentError) { [0][0, 0, 0] = 0 }
     assert_raise(ArgumentError) { [0].freeze[0, 0, 0] = 0 }
     assert_raise(TypeError) { [0][:foo] = 0 }
-    assert_raise(RuntimeError) { [0].freeze[:foo] = 0 }
+    assert_raise(FrozenError) { [0].freeze[:foo] = 0 }
   end
 
   def test_first2
@@ -2146,8 +2146,8 @@ def test_shift2
   end
 
   def test_unshift_error
-    assert_raise(RuntimeError) { [].freeze.unshift('cat') }
-    assert_raise(RuntimeError) { [].freeze.unshift() }
+    assert_raise(FrozenError) { [].freeze.unshift('cat') }
+    assert_raise(FrozenError) { [].freeze.unshift() }
   end
 
   def test_aref
@@ -2208,7 +2208,7 @@ def test_insert
     assert_equal([0, 1, 2], a.insert(-1, 2))
     assert_equal([0, 1, 3, 2], a.insert(-2, 3))
     assert_raise_with_message(IndexError, /-6/) { a.insert(-6, 4) }
-    assert_raise(RuntimeError) { [0].freeze.insert(0)}
+    assert_raise(FrozenError) { [0].freeze.insert(0)}
     assert_raise(ArgumentError) { [0].freeze.insert }
   end
 
@@ -2389,8 +2389,8 @@ def test_flatten_error
     assert_raise(ArgumentError) { a.flatten!(1, 2) }
     assert_raise(TypeError) { a.flatten!(:foo) }
     assert_raise(ArgumentError) { f.flatten!(1, 2) }
-    assert_raise(RuntimeError) { f.flatten! }
-    assert_raise(RuntimeError) { f.flatten!(:foo) }
+    assert_raise(FrozenError) { f.flatten! }
+    assert_raise(FrozenError) { f.flatten!(:foo) }
   end
 
   def test_shuffle
@@ -2728,7 +2728,7 @@ def test_rotate!
     assert_equal([], a.rotate!(13))
     assert_equal([], a.rotate!(-13))
     a = [].freeze
-    assert_raise_with_message(RuntimeError, /can\'t modify frozen/) {a.rotate!}
+    assert_raise_with_message(FrozenError, /can\'t modify frozen/) {a.rotate!}
     a = [1,2,3]
     assert_raise(ArgumentError) { a.rotate!(1, 1) }
   end
diff --git a/test/ruby/test_class.rb b/test/ruby/test_class.rb
index bb8a3c574d..ad2caeb8be 100644
--- a/test/ruby/test_class.rb
+++ b/test/ruby/test_class.rb
@@ -443,14 +443,14 @@ def test_singleton_class_of_frozen_object
     obj = Object.new
     c = obj.singleton_class
     obj.freeze
-    assert_raise_with_message(RuntimeError, /frozen object/) {
+    assert_raise_with_message(FrozenError, /frozen object/) {
       c.class_eval {def f; end}
     }
   end
 
   def test_singleton_class_message
     c = Class.new.freeze
-    assert_raise_with_message(RuntimeError, /frozen Class/) {
+    assert_raise_with_message(FrozenError, /frozen Class/) {
       def c.f; end
     }
   end
diff --git a/test/ruby/test_enumerator.rb b/test/ruby/test_enumerator.rb
index 51f69be37d..235dfbfc9b 100644
--- a/test/ruby/test_enumerator.rb
+++ b/test/ruby/test_enumerator.rb
@@ -79,7 +79,7 @@ def test_initialize
     enum = @obj.to_enum
     assert_raise(NoMethodError) { enum.each {} }
     enum.freeze
-    assert_raise(RuntimeError) {
+    assert_raise(FrozenError) {
       capture_io do
         # warning: Enumerator.new without a block is deprecated; use Object#to_enum
         enum.__send__(:initialize, @obj, :foo)
@@ -440,7 +440,7 @@ def test_generator
     assert_equal([1, 2, 3], a)
 
     g.freeze
-    assert_raise(RuntimeError) {
+    assert_raise(FrozenError) {
       g.__send__ :initialize, proc { |y| y << 4 << 5 }
     }
 
diff --git a/test/ruby/test_eval.rb b/test/ruby/test_eval.rb
index 9f25b771bf..0bc0390d64 100644
--- a/test/ruby/test_eval.rb
+++ b/test/ruby/test_eval.rb
@@ -506,7 +506,7 @@ def test_eval_location_fstring
   def test_fstring_instance_eval
     bug = "[ruby-core:78116] [Bug #12930]".freeze
     assert_same bug, (bug.instance_eval {self})
-    assert_raise(RuntimeError) {
+    assert_raise(FrozenError) {
       bug.instance_eval {@ivar = true}
     }
   end
diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb
index 813afaeee0..ea19ba80a7 100644
--- a/test/ruby/test_hash.rb
+++ b/test/ruby/test_hash.rb
@@ -1031,8 +1031,8 @@ def test_replace2
     assert_raise(TypeError) { h2.replace(1) }
     h2.freeze
     assert_raise(ArgumentError) { h2.replace() }
-    assert_raise(RuntimeError) { h2.replace(h1) }
-    assert_raise(RuntimeError) { h2.replace(42) }
+    assert_raise(FrozenError) { h2.replace(h1) }
+    assert_raise(FrozenError) { h2.replace(42) }
   end
 
   def test_size2
diff --git a/test/ruby/test_lazy_enumerator.rb b/test/ruby/test_lazy_enumerator.rb
index 56890f4b6e..22028283ce 100644
--- a/test/ruby/test_lazy_enumerator.rb
+++ b/test/ruby/test_lazy_enumerator.rb
@@ -32,7 +32,7 @@ def test_initialize
 
     a = [1, 2, 3].lazy
     a.freeze
-    assert_raise(RuntimeError) {
+    assert_raise(FrozenError) {
       a.__send__ :initialize, [4, 5], &->(y, *v) { y << yield(*v) }
     }
   end
diff --git a/test/ruby/test_literal.rb b/test/ruby/test_literal.rb
index 67a383bc3c..cf1a2babd7 100644
--- a/test/ruby/test_literal.rb
+++ b/test/ruby/test_literal.rb
@@ -185,7 +185,7 @@ def test_debug_frozen_string
       str = RubyVM::InstructionSequence.compile(src, f, f, n, opt).eval
       assert_equal("foo-1", str)
       assert_predicate(str, :frozen?)
-      assert_raise_with_message(RuntimeError, /created at #{Regexp.quote(f)}:#{n}/) {
+      assert_raise_with_message(FrozenError, /created at #{Regexp.quote(f)}:#{n}/) {
         str << "x"
       }
     end
diff --git a/test/ruby/test_marshal.rb b/test/ruby/test_marshal.rb
index 48a7d03428..80ec0b1684 100644
--- a/test/ruby/test_marshal.rb
+++ b/test/ruby/test_marshal.rb
@@ -568,7 +568,7 @@ def test_marshal_dump_ivar
     s.instance_variable_set(:@t, 42)
     t = Bug8276.new(s)
     s = Marshal.dump(t)
-    assert_raise(RuntimeError) {Marshal.load(s)}
+    assert_raise(FrozenError) {Marshal.load(s)}
   end
 
   def test_marshal_load_ivar
diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb
index d1c5d53822..d4c95b18e1 100644
--- a/test/ruby/test_module.rb
+++ b/test/ruby/test_module.rb
@@ -636,15 +636,15 @@ def self.baz; end
       def bar; end
     end
     m.freeze
-    assert_raise(RuntimeError) do
+    assert_raise(FrozenError) do
       m.module_eval do
         def foo; end
       end
     end
-    assert_raise(RuntimeError) do
+    assert_raise(FrozenError) do
       m.__send__ :private, :bar
     end
-    assert_raise(RuntimeError) do
+    assert_raise(FrozenError) do
       m.private_class_method :baz
     end
   end
@@ -949,7 +949,7 @@ def test_singleton_constants
   def test_frozen_module
     m = Module.new
     m.freeze
-    assert_raise(RuntimeError) do
+    assert_raise(FrozenError) do
       m.instance_eval { undef_method(:foo) }
     end
   end
@@ -957,7 +957,7 @@ def test_frozen_module
   def test_frozen_class
     c = Class.new
     c.freeze
-    assert_raise(RuntimeError) do
+    assert_raise(FrozenError) do
       c.instance_eval { undef_method(:foo) }
     end
   end
@@ -967,7 +967,7 @@ def test_frozen_singleton_class
     o = klass.new
     c = class << o; self; end
     c.freeze
-    assert_raise_with_message(RuntimeError, /frozen/) do
+    assert_raise_with_message(FrozenError, /frozen/) do
       c.instance_eval { undef_method(:foo) }
     end
     klass.class_eval do
@@ -2061,17 +2061,17 @@ def test_frozen_visibility
     bug11532 = '[ruby-core:70828] [Bug #11532]'
 
     c = Class.new {const_set(:A, 1)}.freeze
-    assert_raise_with_message(RuntimeError, /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(RuntimeError, /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(RuntimeError, /frozen class/, bug11532) {
+    assert_raise_with_message(FrozenError, /frozen class/, bug11532) {
       c.class_eval {deprecate_constant :A}
     }
   end
diff --git a/test/ruby/test_object.rb b/test/ruby/test_object.rb
index e55a09dc23..c25dcf9c37 100644
--- a/test/ruby/test_object.rb
+++ b/test/ruby/test_object.rb
@@ -99,12 +99,12 @@ def test_kind_of
   def test_taint_frozen_obj
     o = Object.new
     o.freeze
-    assert_raise(RuntimeError) { o.taint }
+    assert_raise(FrozenError) { o.taint }
 
     o = Object.new
     o.taint
     o.freeze
-    assert_raise(RuntimeError) { o.untaint }
+    assert_raise(FrozenError) { o.untaint }
   end
 
   def test_freeze_immediate
@@ -123,7 +123,7 @@ def test_frozen_error_message
       attr_accessor :foo
     }
     obj = klass.new.freeze
-    assert_raise_with_message(RuntimeError, /#{name}/) {
+    assert_raise_with_message(FrozenError, /#{name}/) {
       obj.foo = 1
     }
   end
@@ -399,7 +399,7 @@ def object_id; 1; end
   def test_remove_method
     c = Class.new
     c.freeze
-    assert_raise(RuntimeError) do
+    assert_raise(FrozenError) do
       c.instance_eval { remove_method(:foo) }
     end
 
@@ -807,7 +807,7 @@ class ToS\u{3042}
     class<<x;self;end.class_eval {define_method(:to_s) {name}}
     assert_same(name, x.to_s)
     assert_not_predicate(name, :tainted?)
-    assert_raise(RuntimeError) {name.taint}
+    assert_raise(FrozenError) {name.taint}
     assert_equal("X", [x].join(""))
     assert_not_predicate(name, :tainted?)
     assert_not_predicate(eval('"X".freeze'), :tainted?)
@@ -899,7 +899,7 @@ def assert_not_initialize_copy
     b = yield
     assert_nothing_raised("copy") {a.instance_eval {initialize_copy(b)}}
     c = a.dup.freeze
-    assert_raise(RuntimeError, "frozen") {c.instance_eval {initialize_copy(b)}}
+    assert_raise(FrozenError, "frozen") {c.instance_eval {initialize_copy(b)}}
     d = a.dup.trust
     [a, b, c, d]
   end
diff --git a/test/ruby/test_pack.rb b/test/ruby/test_pack.rb
index f5b3266803..62a7a54e8d 100644
--- a/test/ruby/test_pack.rb
+++ b/test/ruby/test_pack.rb
@@ -821,7 +821,7 @@ def test_pack_resize
   def test_pack_with_buffer
     buf = String.new(capacity: 100)
 
-    assert_raise_with_message(RuntimeError, /frozen/) {
+    assert_raise_with_message(FrozenError, /frozen/) {
       [0xDEAD_BEEF].pack('N', buffer: 'foo'.freeze)
     }
     assert_raise_with_message(TypeError, /must be String/) {
diff --git a/test/ruby/test_rand.rb b/test/ruby/test_rand.rb
index af771a2a8f..882d33fb40 100644
--- a/test/ruby/test_rand.rb
+++ b/test/ruby/test_rand.rb
@@ -507,7 +507,7 @@ def test_marshal
   def test_initialize_frozen
     r = Random.new(0)
     r.freeze
-    assert_raise(RuntimeError, '[Bug #6540]') do
+    assert_raise(FrozenError, '[Bug #6540]') do
       r.__send__(:initialize, r)
     end
   end
@@ -516,7 +516,7 @@ def test_marshal_load_frozen
     r = Random.new(0)
     d = r.__send__(:marshal_dump)
     r.freeze
-    assert_raise(RuntimeError, '[Bug #6540]') do
+    assert_raise(FrozenError, '[Bug #6540]') do
       r.__send__(:marshal_load, d)
     end
   end
diff --git a/test/ruby/test_range.rb b/test/ruby/test_range.rb
index 77d026c912..fef7acc062 100644
--- a/test/ruby/test_range.rb
+++ b/test/ruby/test_range.rb
@@ -22,7 +22,7 @@ def obj.<=>(other)
   def test_frozen_initialize
     r = Range.allocate
     r.freeze
-    assert_raise(RuntimeError){r.__send__(:initialize, 1, 2)}
+    assert_raise(FrozenError){r.__send__(:initialize, 1, 2)}
   end
 
   def test_range_string
diff --git a/test/ruby/test_rubyoptions.rb b/test/ruby/test_rubyoptions.rb
index 09b25da2d3..c3ec35d345 100644
--- a/test/ruby/test_rubyoptions.rb
+++ b/test/ruby/test_rubyoptions.rb
@@ -928,7 +928,7 @@ def test_frozen_string_literal
 
   def test_frozen_string_literal_debug
     with_debug_pat = /created at/
-    wo_debug_pat = /can\'t modify frozen String \(RuntimeError\)\n\z/
+    wo_debug_pat = /can\'t modify frozen String \(FrozenError\)\n\z/
     frozen = [
       ["--enable-frozen-string-literal", true],
       ["--disable-frozen-string-literal", false],
diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb
index 7dd76f76f7..81e03aab30 100644
--- a/test/ruby/test_string.rb
+++ b/test/ruby/test_string.rb
@@ -62,12 +62,12 @@ def test_s_new
   def test_initialize
     str = S("").freeze
     assert_equal("", str.__send__(:initialize))
-    assert_raise(RuntimeError){ str.__send__(:initialize, 'abc') }
-    assert_raise(RuntimeError){ str.__send__(:initialize, capacity: 1000) }
-    assert_raise(RuntimeError){ str.__send__(:initialize, 'abc', capacity: 1000) }
-    assert_raise(RuntimeError){ str.__send__(:initialize, encoding: 'euc-jp') }
-    assert_raise(RuntimeError){ str.__send__(:initialize, 'abc', encoding: 'euc-jp') }
-    assert_raise(RuntimeError){ str.__send__(:initialize, 'abc', capacity: 1000, encoding: 'euc-jp') }
+    assert_raise(FrozenError){ str.__send__(:initialize, 'abc') }
+    assert_raise(FrozenError){ str.__send__(:initialize, capacity: 1000) }
+    assert_raise(FrozenError){ str.__send__(:initialize, 'abc', capacity: 1000) }
+    assert_raise(FrozenError){ str.__send__(:initialize, encoding: 'euc-jp') }
+    assert_raise(FrozenError){ str.__send__(:initialize, 'abc', encoding: 'euc-jp') }
+    assert_raise(FrozenError){ str.__send__(:initialize, 'abc', capacity: 1000, encoding: 'euc-jp') }
   end
 
   def test_initialize_nonstring
@@ -491,7 +491,7 @@ def test_chomp!
     assert_equal(S("a").hash, S("a\u0101").chomp!(S("\u0101")).hash, '[ruby-core:22414]')
 
     s = S("").freeze
-    assert_raise_with_message(RuntimeError, /frozen/) {s.chomp!}
+    assert_raise_with_message(FrozenError, /frozen/) {s.chomp!}
 
     s = S("ax")
     o = Struct.new(:s).new(s)
@@ -499,7 +499,7 @@ def o.to_str
       s.freeze
       "x"
     end
-    assert_raise_with_message(RuntimeError, /frozen/) {s.chomp!(o)}
+    assert_raise_with_message(FrozenError, /frozen/) {s.chomp!(o)}
 
     s = S("hello")
     assert_equal("hel", s.chomp!('lo'))
@@ -617,7 +617,7 @@ def test_concat
     expected = S("\u0300".encode(Encoding::UTF_16LE))
     assert_equal(expected, result, bug7090)
     assert_raise(TypeError) { 'foo' << :foo }
-    assert_raise(RuntimeError) { 'foo'.freeze.concat('bar') }
+    assert_raise(FrozenError) { 'foo'.freeze.concat('bar') }
   end
 
   def test_concat_literals
@@ -1367,10 +1367,10 @@ def test_replace
     assert_equal(s2, s)
 
     fs = "".freeze
-    assert_raise(RuntimeError) { fs.replace("a") }
-    assert_raise(RuntimeError) { fs.replace(fs) }
+    assert_raise(FrozenError) { fs.replace("a") }
+    assert_raise(FrozenError) { fs.replace(fs) }
     assert_raise(ArgumentError) { fs.replace() }
-    assert_raise(RuntimeError) { fs.replace(42) }
+    assert_raise(FrozenError) { fs.replace(42) }
   end
 
   def test_reverse
@@ -2272,7 +2272,7 @@ def test_mod_check
   end
 
   def test_frozen_check
-    assert_raise(RuntimeError) {
+    assert_raise(FrozenError) {
       s = ""
       s.sub!(/\A/) { s.freeze; "zzz" }
     }
@@ -2710,7 +2710,7 @@ def test_delete_prefix_bang
     assert_equal("bba", s)
 
     s = S("ax").freeze
-    assert_raise_with_message(RuntimeError, /frozen/) {s.delete_prefix!("a")}
+    assert_raise_with_message(FrozenError, /frozen/) {s.delete_prefix!("a")}
 
     s = S("ax")
     o = Struct.new(:s).new(s)
@@ -2718,7 +2718,7 @@ def o.to_str
       s.freeze
       "a"
     end
-    assert_raise_with_message(RuntimeError, /frozen/) {s.delete_prefix!(o)}
+    assert_raise_with_message(FrozenError, /frozen/) {s.delete_prefix!(o)}
   end
 
   def test_delete_suffix
@@ -2778,7 +2778,7 @@ def test_delete_suffix_bang
     assert_raise(TypeError) { 'hello'.delete_suffix!(/hel/) }
 
     s = S("hello").freeze
-    assert_raise_with_message(RuntimeError, /frozen/) {s.delete_suffix!('lo')}
+    assert_raise_with_message(FrozenError, /frozen/) {s.delete_suffix!('lo')}
 
     s = S("ax")
     o = Struct.new(:s).new(s)
@@ -2786,7 +2786,7 @@ def o.to_str
       s.freeze
       "x"
     end
-    assert_raise_with_message(RuntimeError, /frozen/) {s.delete_suffix!(o)}
+    assert_raise_with_message(FrozenError, /frozen/) {s.delete_suffix!(o)}
 
     s = S("hello")
     assert_equal("hel", s.delete_suffix!('lo'))
diff --git a/test/ruby/test_thread.rb b/test/ruby/test_thread.rb
index 6e2f594970..9242f7f480 100644
--- a/test/ruby/test_thread.rb
+++ b/test/ruby/test_thread.rb
@@ -102,7 +102,7 @@ def test_thread_variable_strings_and_symbols_are_the_same_key
   def test_thread_variable_frozen
     t = Thread.new { }.join
     t.freeze
-    assert_raise(RuntimeError) do
+    assert_raise(FrozenError) do
       t.thread_variable_set(:foo, "bar")
     end
   end
@@ -547,7 +547,7 @@ def test_thread_local_fetch
   end
 
   def test_thread_local_security
-    assert_raise(RuntimeError) do
+    assert_raise(FrozenError) do
       Thread.new do
         Thread.current[:foo] = :bar
         Thread.current.freeze
diff --git a/test/ruby/test_transcode.rb b/test/ruby/test_transcode.rb
index 0ec9e6e7b9..44d238ffd2 100644
--- a/test/ruby/test_transcode.rb
+++ b/test/ruby/test_transcode.rb
@@ -13,8 +13,8 @@ def test_errors
     assert_raise(Encoding::UndefinedConversionError) { "\x80".encode('utf-8','ASCII-8BIT') }
     assert_raise(Encoding::InvalidByteSequenceError) { "\x80".encode('utf-8','US-ASCII') }
     assert_raise(Encoding::UndefinedConversionError) { "\xA5".encode('utf-8','iso-8859-3') }
-    assert_raise(RuntimeError) { 'hello'.freeze.encode!('iso-8859-1') }
-    assert_raise(RuntimeError) { '\u3053\u3093\u306b\u3061\u306f'.freeze.encode!('iso-8859-1') } # こんにちは
+    assert_raise(FrozenError) { 'hello'.freeze.encode!('iso-8859-1') }
+    assert_raise(FrozenError) { '\u3053\u3093\u306b\u3061\u306f'.freeze.encode!('iso-8859-1') } # こんにちは
   end
 
   def test_arguments
diff --git a/test/ruby/test_variable.rb b/test/ruby/test_variable.rb
index 3a55189ed7..a9b1fd50ff 100644
--- a/test/ruby/test_variable.rb
+++ b/test/ruby/test_variable.rb
@@ -137,14 +137,14 @@ def test_special_constant_ivars
       assert_empty v.instance_variables
       msg = "can't modify frozen #{v.class}"
 
-      assert_raise_with_message(RuntimeError, msg) do
+      assert_raise_with_message(FrozenError, msg) do
         v.instance_variable_set(:@foo, :bar)
       end
 
       assert_nil EnvUtil.suppress_warning {v.instance_variable_get(:@foo)}
       assert_not_send([v, :instance_variable_defined?, :@foo])
 
-      assert_raise_with_message(RuntimeError, msg) do
+      assert_raise_with_message(FrozenError, msg) do
         v.remove_instance_variable(:@foo)
       end
     end
diff --git a/test/stringio/test_stringio.rb b/test/stringio/test_stringio.rb
index f97ac877fc..f5169f641a 100644
--- a/test/stringio/test_stringio.rb
+++ b/test/stringio/test_stringio.rb
@@ -722,9 +722,9 @@ def test_frozen
     s = StringIO.new
     s.freeze
     bug = '[ruby-core:33648]'
-    assert_raise(RuntimeError, bug) {s.puts("foo")}
-    assert_raise(RuntimeError, bug) {s.string = "foo"}
-    assert_raise(RuntimeError, bug) {s.reopen("")}
+    assert_raise(FrozenError, bug) {s.puts("foo")}
+    assert_raise(FrozenError, bug) {s.string = "foo"}
+    assert_raise(FrozenError, bug) {s.reopen("")}
   end
 
   def test_frozen_string
diff --git a/test/test_delegate.rb b/test/test_delegate.rb
index 48bf9cdbf0..5320520de3 100644
--- a/test/test_delegate.rb
+++ b/test/test_delegate.rb
@@ -100,7 +100,7 @@ def test_copy_frozen
     a = [42, :hello].freeze
     d = SimpleDelegator.new(a)
     assert_nothing_raised(bug2679) {d.dup[0] += 1}
-    assert_raise(RuntimeError) {d.clone[0] += 1}
+    assert_raise(FrozenError) {d.clone[0] += 1}
     d.freeze
     assert(d.clone.frozen?)
     assert(!d.dup.frozen?)
@@ -109,7 +109,7 @@ def test_copy_frozen
   def test_frozen
     d = SimpleDelegator.new([1, :foo])
     d.freeze
-    assert_raise(RuntimeError, '[ruby-dev:40314]#1') {d.__setobj__("foo")}
+    assert_raise(FrozenError, '[ruby-dev:40314]#1') {d.__setobj__("foo")}
     assert_equal([1, :foo], d)
   end
 
diff --git a/test/test_set.rb b/test/test_set.rb
index 37b781c5ca..4c6730d141 100644
--- a/test/test_set.rb
+++ b/test/test_set.rb
@@ -693,7 +693,7 @@ def test_freeze
     set << 4
     assert_same orig, set.freeze
     assert_equal true, set.frozen?
-    assert_raise(RuntimeError) {
+    assert_raise(FrozenError) {
       set << 5
     }
     assert_equal 4, set.size
@@ -716,7 +716,7 @@ def test_freeze_clone
     set2 = set1.clone
 
     assert_predicate set2, :frozen?
-    assert_raise(RuntimeError) {
+    assert_raise(FrozenError) {
       set2.add 5
     }
   end
@@ -849,7 +849,7 @@ def test_freeze
     set << 4
     assert_same orig, set.freeze
     assert_equal true, set.frozen?
-    assert_raise(RuntimeError) {
+    assert_raise(FrozenError) {
       set << 5
     }
     assert_equal 4, set.size
@@ -877,7 +877,7 @@ def test_freeze_clone
     set2 = set1.clone
 
     assert_predicate set2, :frozen?
-    assert_raise(RuntimeError) {
+    assert_raise(FrozenError) {
       set2.add 5
     }
   end
-- 
2.15.0

