Skip to content

Commit 2cc999d

Browse files
committed
Rewrite comments about dropping and leaking.
1 parent 769425a commit 2cc999d

File tree

1 file changed

+26
-16
lines changed

1 file changed

+26
-16
lines changed

library/core/src/clone.rs

+26-16
Original file line numberDiff line numberDiff line change
@@ -336,19 +336,29 @@ pub struct AssertParamIsCopy<T: Copy + ?Sized> {
336336
/// // The offset of `self.contents` is dynamic because it depends on the alignment of T
337337
/// // which can be dynamic (if `T = dyn SomeTrait`). Therefore, we have to obtain it
338338
/// // dynamically by examining `self`, rather than using `offset_of!`.
339-
/// let offset_of_contents =
340-
/// (&raw const self.contents).byte_offset_from_unsigned(&raw const *self);
341-
///
342-
/// // Since `flag` implements `Copy`, we can just copy it.
343-
/// // We use `pointer::write()` instead of assignment because the destination must be
344-
/// // assumed to be uninitialized, whereas an assignment assumes it is initialized.
345-
/// dest.add(offset_of!(Self, flag)).cast::<bool>().write(self.flag);
346-
///
347-
/// // Note: if `flag` owned any resources (i.e. had a `Drop` implementation), then we
348-
/// // must prepare to drop it in case `self.contents.clone_to_uninit()` panics.
349-
/// // In this simple case, where we have exactly one field for which `mem::needs_drop()`
350-
/// // might be true (`contents`), we don’t need to care about cleanup or ordering.
351-
/// self.contents.clone_to_uninit(dest.add(offset_of_contents));
339+
/// //
340+
/// // SAFETY: `self` by definition points somewhere before `&self.contents` in the same
341+
/// // allocation.
342+
/// let offset_of_contents = unsafe {
343+
/// (&raw const self.contents).byte_offset_from_unsigned(self)
344+
/// };
345+
///
346+
/// // Clone each field of `self` into `dest`.
347+
/// //
348+
/// // Since `flag` is `Sized`, we could also clone it as
349+
/// // dest.add(offset_of!(Self, flag)).cast::<bool>().write(self.flag.clone());
350+
/// // Since it is `Copy` (and therefore does not have a destructor), we could even write
351+
/// // *dest.add(offset_of!(Self, flag)) = self.flag;
352+
/// // but that must not be used for types with destructors, since it would read the place
353+
/// // in order to drop the old value. We have chosen to do neither of those, to demonstrate
354+
/// // the most general pattern.
355+
/// //
356+
/// // SAFETY: The caller must provide a `dest` such that these offsets are valid
357+
/// // to write to.
358+
/// unsafe {
359+
/// self.flag.clone_to_uninit(dest.add(offset_of!(Self, flag)));
360+
/// self.contents.clone_to_uninit(dest.add(offset_of_contents));
361+
/// }
352362
///
353363
/// // All fields of the struct have been initialized, therefore the struct is initialized,
354364
/// // and we have satisfied our `unsafe impl CloneToUninit` obligations.
@@ -370,6 +380,7 @@ pub struct AssertParamIsCopy<T: Copy + ?Sized> {
370380
///
371381
/// assert_eq!(first.contents, [1, 2, 3, 4]);
372382
/// assert_eq!(second.contents, [10, 20, 30, 40]);
383+
/// assert_eq!(second.flag, true);
373384
/// }
374385
/// ```
375386
///
@@ -414,9 +425,8 @@ pub unsafe trait CloneToUninit {
414425
/// read or dropped, because even if it was previously valid, it may have been partially
415426
/// overwritten.
416427
///
417-
/// The caller may also need to take care to deallocate the allocation pointed to by `dest`,
418-
/// if applicable, to avoid a memory leak, and may need to take other precautions to ensure
419-
/// soundness in the presence of unwinding.
428+
/// The caller may wish to to take care to deallocate the allocation pointed to by `dest`,
429+
/// if applicable, to avoid a memory leak (but this is not a requirement).
420430
///
421431
/// Implementors should avoid leaking values by, upon unwinding, dropping all component values
422432
/// that might have already been created. (For example, if a `[Foo]` of length 3 is being

0 commit comments

Comments
 (0)