Project

General

Profile

Feature #16175 » clone-freeze-true-16175.patch

jeremyevans0 (Jeremy Evans), 09/23/2019 11:06 PM

View differences:

object.c
}
}
static int freeze_opt(int argc, VALUE *argv);
static VALUE immutable_obj_clone(VALUE obj, int kwfreeze);
static VALUE mutable_obj_clone(VALUE obj, int kwfreeze);
static VALUE freeze_opt(int argc, VALUE *argv);
static VALUE immutable_obj_clone(VALUE obj, VALUE kwfreeze);
static VALUE mutable_obj_clone(VALUE obj, VALUE kwfreeze);
PUREFUNC(static inline int special_object_p(VALUE obj)); /*!< \private */
static inline int
special_object_p(VALUE obj)
......
/*
* call-seq:
* obj.clone(freeze: true) -> an_object
* obj.clone(freeze: frozen?) -> an_object
*
* Produces a shallow copy of <i>obj</i>---the instance variables of
* <i>obj</i> are copied, but not the objects they reference.
* #clone copies the frozen (unless +:freeze+ keyword argument is
* given with a false value) and tainted state of <i>obj</i>. See
* also the discussion under Object#dup.
* By default, #clone copies the frozen state of the object, but the
* +:freeze+ keyword can override this. See also the discussion under
* Object#dup.
*
* class Klass
* attr_accessor :str
......
static VALUE
rb_obj_clone2(int argc, VALUE *argv, VALUE obj)
{
int kwfreeze = freeze_opt(argc, argv);
VALUE kwfreeze = freeze_opt(argc, argv);
if (!special_object_p(obj))
return mutable_obj_clone(obj, kwfreeze);
return immutable_obj_clone(obj, kwfreeze);
......
VALUE
rb_immutable_obj_clone(int argc, VALUE *argv, VALUE obj)
{
int kwfreeze = freeze_opt(argc, argv);
VALUE kwfreeze = freeze_opt(argc, argv);
return immutable_obj_clone(obj, kwfreeze);
}
static int
static VALUE
freeze_opt(int argc, VALUE *argv)
{
static ID keyword_ids[1];
VALUE opt;
VALUE kwfreeze;
VALUE kwfreeze = Qundef;
if (!keyword_ids[0]) {
CONST_ID(keyword_ids[0], "freeze");
......
rb_scan_args(argc, argv, "0:", &opt);
if (!NIL_P(opt)) {
rb_get_kwargs(opt, keyword_ids, 0, 1, &kwfreeze);
if (kwfreeze == Qfalse) return FALSE;
if (kwfreeze == Qfalse) return kwfreeze;
if (kwfreeze != Qundef && kwfreeze != Qtrue) {
rb_raise(rb_eArgError, "unexpected value for freeze: %"PRIsVALUE,
rb_obj_class(kwfreeze));
}
}
return TRUE;
return kwfreeze;
}
static VALUE
immutable_obj_clone(VALUE obj, int kwfreeze)
immutable_obj_clone(VALUE obj, VALUE kwfreeze)
{
if (!kwfreeze)
if (kwfreeze == Qfalse)
rb_raise(rb_eArgError, "can't unfreeze %"PRIsVALUE,
rb_obj_class(obj));
return obj;
}
static VALUE
mutable_obj_clone(VALUE obj, int kwfreeze)
mutable_obj_clone(VALUE obj, VALUE kwfreeze)
{
VALUE clone, singleton;
......
init_copy(clone, obj);
rb_funcall(clone, id_init_clone, 1, obj);
if (kwfreeze) {
switch (kwfreeze) {
case Qtrue:
RBASIC(clone)->flags |= FL_FREEZE;
break;
case Qundef:
RBASIC(clone)->flags |= RBASIC(obj)->flags & FL_FREEZE;
break;
default:
break;
}
return clone;
test/ruby/test_object.rb
a = Object.new
def a.b; 2 end
c = a.clone
assert_equal(false, c.frozen?)
assert_equal(2, c.b)
c = a.clone(freeze: true)
assert_equal(true, c.frozen?)
assert_equal(2, c.b)
a.freeze
c = a.clone
assert_equal(true, c.frozen?)
(2-2/2)