15. Ownership and Destruction

15.1. Ownership

Legality Rules

15.1:1 Ownership is a property of values that is central to the resource management model of Rust.

15.1:2 An owner is a variable that holds a value.

15.1:3 A value shall have only one owner.

15.2. Initialization

Legality Rules

15.2:1 Initialization is the act of supplying an initial value to a variable.

15.2:2 When a variable holds a value, the variable is considered to be initialized.

15.2:3 When a variable lacks a value or its value has been passed by move, the variable is considered to be uninitialized.

15.2:4 A variable shall be initialized before it is accessed.

Runtime Semantics

15.2:5 All memory starts as uninitialized.

Examples

15.2:6 Variable a is initialized.

let a: i32 = 42;

15.2:7 Variable b starts off as uninitialized, but is later initialized by virtue of the assignment statement.

let b: i32;
b = 42;

15.2:8 Variable c starts off initialized, but is later uninitialized by virtue of a transfer by move.

use core::sync::atomic::AtomicI32;

let c: AtomicI32 = AtomicI32::new(42);
let d: AtomicI32 = c;

15.3. References

Legality Rules

15.3:1 A reference is a value of a reference type. A reference can be obtained explicitly by using a borrow expression or implicitly in certain scenarios.

15.3:2 A referent is the value pointed-to by a reference.

15.3:3 A reference shall point to an initialized referent.

15.3:4 The lifetime of a referent shall be at least as long as the lifetime of its reference.

15.3:5 A reference is active from the point of obtaining its referent upto the last use of the reference, prior to another assignment to the reference or the end of the scope of the reference.

15.3:6 A referent shall not be passed by move while a reference to it is active.

15.3:7 A referent shall not be modified while a reference to it is active.

15.3:8 An immutable reference is a value of a shared reference type, and prevents the mutation of its referent.

15.3:9 A mutable reference is a value of a mutable reference type, and allows the mutation of its referent.

15.3:10 The referent of an immutable reference shall be mutated only when the type of the referent is subject to interior mutability.

15.3:11 While a mutable reference is active, no other reference shall refer to a value that overlaps with the referent of the mutable reference.

Undefined Behavior

15.3:12 It is undefined behavior to access a value through aliasing mutable references from unsafe context.

Examples

let immutable_reference: &i32 = &42;
let mutable_reference: &mut i32 = &mut 42;

15.4. Borrowing

Legality Rules

15.4:1 Borrowing is the process of temporarily associating a reference with a value without transferring ownership permanently.

15.4:2 A borrow is a reference produced by borrowing.

15.4:3 An implicit borrow is a borrow that is not present syntactically in program text. An implicit borrow occurs in the following contexts:

15.4:11 An implicit borrow may be an immutable borrow or a mutable borrow if required.

15.4:12 An immutable borrow is an immutable reference produced by borrowing.

15.4:13 A mutable borrow is a mutable reference produced by borrowing.

15.4:14 Borrowing a field of a union type borrows all remaining fields using the same lifetime.

15.4:15 Immutably borrowing a value proceeds as follows:

  1. 15.4:16 ??? (this should describe the order of borrowing and when the borrow is returned)

  2. 15.4:17 An immutable borrow of type &'a T is created, where lifetime 'a is replaced by a lifetime variable, and T is replaced by the borrowed type.

  3. 15.4:18 Lifetime inference is performed.

  4. 15.4:19 The immutable borrow is checked against other borrows and by move passing within the enclosing item.

  5. 15.4:20 An immutable reference to the borrowed value is produced.

  6. 15.4:21 The immutable borrow is released immediately after the last usage of its related immutable reference.

15.4:22 Mutably borrowing a value proceeds as follows:

  1. 15.4:23 A mutable borrow of type &'a mut T is created, where lifetime 'a is replaced by a lifetime variable, and T is replaced by the borrowed type.

  2. 15.4:24 Lifetime inference is performed.

  3. 15.4:25 The mutable borrow is checked against other borrows and by move passing within the enclosing item.

  4. 15.4:26 A mutable reference to the borrowed value is produced.

  5. 15.4:27 The mutable borrow is released immediately after the last usage of its related mutable reference.

Examples

let mutable_borrow = &mut 42;
let immutable_borrow = &42;

15.5. Passing Conventions

Legality Rules

15.5:1 A passing convention is the mechanism that defines how a value is transferred between places.

15.5:2 A copy type is a type that implements the core::marker::Copy trait.

15.5:3 A value of a copy type is passed by copy. Passing by copy does not change the owner of the value.

15.5:4 A move type is a type that implements the core::marker::Sized trait and is not a copy type.

15.5:5 A value of a move type is passed by move. Passing by move changes the owner of the value.

15.5:6 A value of a place expression shall be passed by move only when it denotes:

15.5:10 A value of a value expression is always passed by move.

15.5:11 A value not subject to by copy or by move passing convention shall not be passed between places.

Dynamic Semantics

15.5:12 Passing a value by copy from a source owner to a target owner proceeds as follows:

  1. 15.5:13 The value of the source owner is copied.

  2. 15.5:14 The copy is assigned to the target owner.

15.5:15 Passing a value by move from a source owner to a target owner proceeds as follows:

  1. 15.5:16 The value is unassigned from the source owner.

  2. 15.5:17 The value is assigned to the target owner.

Examples

15.5:18 Type i32 is a copy type. By the end of the second let statement, x is the owner of the original 42 and y is the owner of a cloned 42.

let x: i32 = 42;
let y: i32 = x;

15.5:19 Type core::sync::atomic::AtomicI32 is a move type. By the end of the second let statement, x is uninitialized and y is the sole owner of the atomic 42.

use core::sync::atomic::AtomicI32;

let x: AtomicI32 = AtomicI32::new(42);
let y: AtomicI32 = x;

15.6. Destruction

Legality Rules

15.6:1 Destruction is the process of recovering resources associated with a value as it goes out of scope.

15.7. Destructors

Legality Rules

15.7:1 A drop type is a type that implements the core::ops::Drop trait or contains a field that has a drop type.

15.7:2 A destructor is a function that is invoked immediately before the destruction of a value of a drop type.

15.7:3 Dropping a value is the act of invoking the destructor of the related type. Such an object is said to be dropped.

15.7:4 An uninitialized variable is not dropped.

Dynamic Semantics

15.7:5 Dropping an initialized variable proceeds as follows:

  1. 15.7:6 If the drop type implements the core::ops::Drop trait, then core::ops::Drop::drop of the drop type is invoked.

  2. 15.7:7 If the drop type is an array type, then its elements are dropped from the first element to the last element.

  3. 15.7:8 Otherwise, if the drop type is a closure type, then all capture targets whose capture mode is by move mode are dropped in unspecified order.

  4. 15.7:9 Otherwise, if the drop type is an enum type, then the fields of the active enum variant are dropped in declaration order.

  5. 15.7:10 Otherwise, if the drop type is a slice type, then its elements are dropped from the first element to the last element.

  6. 15.7:11 Otherwise, if the drop type is a struct type, then its fields are dropped in declaration order.

  7. 15.7:12 Otherwise, if the drop type is a trait object type, then the destructor of the underlying type is invoked.

  8. 15.7:13 Otherwise, if the drop type is a tuple type, then its fields are dropped in declaration order.

  9. 15.7:14 Otherwise, dropping has no effect.

Examples

struct PrintOnDrop(&'static str);

impl core::ops::Drop for PrintOnDrop {
    fn drop(&mut self) {
        println!("{}", self.0);
    }
}

15.7:15 When object array is dropped, its destructor drops the first element, then the second element.

let array = [PrintOnDrop("first element to be dropped"),
             PrintOnDrop("second element to be dropped")];

15.7:16 Object uninitialized is not dropped.

let uninitialized: PrintOnDrop;

15.8. Drop Scopes

Legality Rules

15.8:1 A drop scope is a region of program text that governs the dropping of values. When control flow leaves a drop scope, all values associated with that drop scope are dropped based on a drop order.

15.8:2 A drop construct is a construct that employs a drop scope. The following constructs are drop constructs:

15.8:7 Drop scopes are nested within one another as follows:

15.8:17 A binding declared in a for loop expression is associated with the drop scope of the block expression of the for loop expression.

15.8:18 A binding declared in an if let expression is associated with the drop scope of the block expression of the if let expression.

15.8:19 A binding declared in a let statement is associated with the drop scope of the block expression that contains the let statement.

15.8:20 A binding declared in a match expression is associated with the drop scope of the match arm of the match expression.

15.8:21 A binding declared in a while let loop expression is associated with the drop scope of the block expression of the while let loop expression.

15.8:22 A value or binding of a function parameter is associated with the drop scope of the function of the function parameter.

15.8:23 A temporary that is not subject to constant promotion is associated with the innermost drop scope that contains the expression which produced the temporary, taking into account drop scope extension. The possible drop scopes are as follows:

15.8.1. Drop Scope Extension

Legality Rules

15.8.1:1 Drop scope extension is the process of extending a drop scope associated with a temporary to prevent the premature dropping of the temporary.

15.8.1:2 An extending pattern is either

15.8.1:5 If the pattern-without-alternation of a let statement is an extending pattern, then the drop scope of the expression of the let statement is extended to the drop scope of the block expression that contains the let statement.

15.8.1:6 An extending expression is either

15.8.1:10 The drop scope of the operand of a borrow expression that is an extending expression is extended to the drop scope of the block expression that contains the let statement.

15.8.1:11 The drop scope of the operand of a borrow expression, a dereference expression, or a field access expression that has an extended drop scope is extended to the drop scope of the expression.

15.8.1:12 The drop scope of the indexed operand of an index expression that has an extended drop scope is extended to the drop scope of the expression.

Examples

15.8.1:13 See Paragraph 15.6.1. for the declaration of PrintOnDrop.

15.8.1:14 The drop scope of the temporary created for expression AtomicI32::new(42) is extended to the drop scope of the block expression.

use core::sync::atomic::AtomicI32;

{
    let ref mut a = AtomicI32::new(42);
    println!("{}", a);
}

15.9. Drop Order

Legality Rules

15.9:1 Drop order is the order by which values are dropped when a drop scope is left.

15.9:2 When a drop scope is left, all values associated with that drop scope are dropped as follows:

15.9:5 When a drop scope of a function is left, then each function parameter is dropped from right to left as follows:

  1. 15.9:6 All bindings introduced by the pattern of the function parameter are dropped in reverse declaration order,

  2. 15.9:7 The value of the function parameter is dropped.

15.9:8 When multiple drop scopes are left at once, the values are dropped from the innermost drop scope to the outermost drop scope.

Examples

15.9:9 See Paragraph 15.6.1. for the declaration of PrintOnDrop.

15.9:10 The drop order of the following variables is b, c, a. Dropping proceeds as follows:

  1. 15.9:11 The scope of the block expression is left first because it is an inner scope.

  2. 15.9:12 b is dropped.

  3. 15.9:13 The outer scope is left.

  4. 15.9:14 c is dropped because dropping occurs in reverse declarative order.

  5. 15.9:15 a is dropped.

let a = PrintOnDrop("3");
{
    let b = PrintOnDrop("1");
}
let c = PrintOnDrop("2");