Skip to content

Commit d2b3d80

Browse files
authored
Merge pull request #1571 from chorman0773/spec-add-identifiers-destructors
Add spec identifier syntax to destructors.md
2 parents b3e33db + 1ddc46d commit d2b3d80

File tree

1 file changed

+63
-0
lines changed

1 file changed

+63
-0
lines changed

src/destructors.md

+63
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
# Destructors
22

3+
r[destructors.intro]
34
When an [initialized] [variable] or [temporary] goes out of
45
[scope](#drop-scopes), its *destructor* is run, or it is *dropped*. [Assignment]
56
also runs the destructor of its left-hand operand, if it's initialized. If a
67
variable has been partially initialized, only its initialized fields are
78
dropped.
89

10+
r[destructors.operation]
911
The destructor of a type `T` consists of:
1012

1113
1. If `T: Drop`, calling [`<T as std::ops::Drop>::drop`](std::ops::Drop::drop)
@@ -20,6 +22,7 @@ The destructor of a type `T` consists of:
2022
* [Trait objects] run the destructor of the underlying type.
2123
* Other types don't result in any further drops.
2224

25+
r[destructors.drop_in_place]
2326
If a destructor must be run manually, such as when implementing your own smart
2427
pointer, [`std::ptr::drop_in_place`] can be used.
2528

@@ -57,48 +60,84 @@ core::mem::forget(partial_move.1);
5760

5861
## Drop scopes
5962

63+
r[destructors.scope]
64+
65+
r[destructors.scope.intro]
6066
Each variable or temporary is associated to a *drop scope*. When control flow
6167
leaves a drop scope all variables associated to that scope are dropped in
6268
reverse order of declaration (for variables) or creation (for temporaries).
6369

70+
r[destructors.scope.desugaring]
6471
Drop scopes are determined after replacing [`for`], [`if let`], and
6572
[`while let`] expressions with the equivalent expressions using [`match`].
73+
74+
r[destructors.scope.operators]
6675
Overloaded operators are not distinguished from built-in operators and [binding
6776
modes] are not considered.
6877

78+
r[destructors.scope.list]
6979
Given a function, or closure, there are drop scopes for:
7080

81+
r[destructors.scope.function]
7182
* The entire function
83+
84+
r[destructors.scope.statement]
7285
* Each [statement]
86+
87+
r[destructors.scope.expression]
7388
* Each [expression]
89+
90+
r[destructors.scope.block]
7491
* Each block, including the function body
7592
* In the case of a [block expression], the scope for the block and the
7693
expression are the same scope.
94+
95+
r[destructors.scope.match-arm]
7796
* Each arm of a `match` expression
7897

98+
r[destructors.scope.nesting]
7999
Drop scopes are nested within one another as follows. When multiple scopes are
80100
left at once, such as when returning from a function, variables are dropped
81101
from the inside outwards.
82102

103+
r[destructors.scope.nesting.function]
83104
* The entire function scope is the outer most scope.
105+
106+
r[destructors.scope.nesting.function-body]
84107
* The function body block is contained within the scope of the entire function.
108+
109+
r[destructors.scope.nesting.expr-statement]
85110
* The parent of the expression in an expression statement is the scope of the
86111
statement.
112+
113+
r[destructors.scope.nesting.let-initializer]
87114
* The parent of the initializer of a [`let` statement] is the `let` statement's
88115
scope.
116+
117+
r[destructors.scope.nesting.statement]
89118
* The parent of a statement scope is the scope of the block that contains the
90119
statement.
120+
121+
r[destructors.scope.nesting.match-guard]
91122
* The parent of the expression for a `match` guard is the scope of the arm that
92123
the guard is for.
124+
125+
r[destructors.scope.nesting.match-arm]
93126
* The parent of the expression after the `=>` in a `match` expression is the
94127
scope of the arm that it's in.
128+
129+
r[destructors.scope.nesting.match]
95130
* The parent of the arm scope is the scope of the `match` expression that it
96131
belongs to.
132+
133+
r[destructors.scope.nesting.other]
97134
* The parent of all other scopes is the scope of the immediately enclosing
98135
expression.
99136

100137
### Scopes of function parameters
101138

139+
r[destructors.scope.params]
140+
102141
All function parameters are in the scope of the entire function body, so are
103142
dropped last when evaluating the function. Each actual function parameter is
104143
dropped after any bindings introduced in that parameter's pattern.
@@ -125,6 +164,9 @@ patterns_in_parameters(
125164

126165
### Scopes of local variables
127166

167+
r[destructors.scope.bindings]
168+
169+
r[destructors.scope.bindings.intro]
128170
Local variables declared in a `let` statement are associated to the scope of
129171
the block that contains the `let` statement. Local variables declared in a
130172
`match` expression are associated to the arm scope of the `match` arm that they
@@ -144,15 +186,20 @@ let declared_first = PrintOnDrop("Dropped last in outer scope");
144186
let declared_last = PrintOnDrop("Dropped first in outer scope");
145187
```
146188

189+
r[destructors.scope.bindings.match-pattern-order]
147190
If multiple patterns are used in the same arm for a `match` expression, then an
148191
unspecified pattern will be used to determine the drop order.
149192

150193
### Temporary scopes
151194

195+
r[destructors.scope.temporary]
196+
197+
r[destructors.scope.temporary.intro]
152198
The *temporary scope* of an expression is the scope that is used for the
153199
temporary variable that holds the result of that expression when used in a
154200
[place context], unless it is [promoted].
155201

202+
r[destructors.scope.temporary.enclosing]
156203
Apart from lifetime extension, the temporary scope of an expression is the
157204
smallest scope that contains the expression and is one of the following:
158205

@@ -215,6 +262,8 @@ match PrintOnDrop("Matched value in final expression") {
215262

216263
### Operands
217264

265+
r[destructors.scope.operands]
266+
218267
Temporaries are also created to hold the result of operands to an expression
219268
while the other operands are evaluated. The temporaries are associated to the
220269
scope of the expression with that operand. Since the temporaries are moved from
@@ -245,6 +294,8 @@ loop {
245294

246295
### Constant promotion
247296

297+
r[destructors.scope.const-promotion]
298+
248299
Promotion of a value expression to a `'static` slot occurs when the expression
249300
could be written in a constant and borrowed, and that borrow could be dereferenced
250301
where
@@ -256,9 +307,12 @@ always has the type `&'static Option<_>`, as it contains nothing disallowed).
256307

257308
### Temporary lifetime extension
258309

310+
r[destructors.scope.lifetime-extension]
311+
259312
> **Note**: The exact rules for temporary lifetime extension are subject to
260313
> change. This is describing the current behavior only.
261314
315+
r[destructors.scope.lifetime-extension.let]
262316
The temporary scopes for expressions in `let` statements are sometimes
263317
*extended* to the scope of the block containing the `let` statement. This is
264318
done when the usual temporary scope would be too small, based on certain
@@ -271,6 +325,7 @@ let x = &mut 0;
271325
println!("{}", x);
272326
```
273327

328+
r[destructors.scope.lifetime-extension.sub-expressions]
274329
If a [borrow][borrow expression], [dereference][dereference expression],
275330
[field][field expression], or [tuple indexing expression] has an extended
276331
temporary scope then so does its operand. If an [indexing expression] has an
@@ -279,6 +334,9 @@ temporary scope.
279334

280335
#### Extending based on patterns
281336

337+
r[destructors.scope.lifetime-extension.patterns]
338+
339+
r[destructors.scope.lifetime-extension.patterns.extending]
282340
An *extending pattern* is either
283341

284342
* An [identifier pattern] that binds by reference or mutable reference.
@@ -289,11 +347,14 @@ An *extending pattern* is either
289347
So `ref x`, `V(ref x)` and `[ref x, y]` are all extending patterns, but `x`,
290348
`&ref x` and `&(ref x,)` are not.
291349

350+
r[destructors.scope.lifetime-extension.patterns.let]
292351
If the pattern in a `let` statement is an extending pattern then the temporary
293352
scope of the initializer expression is extended.
294353

295354
#### Extending based on expressions
296355

356+
r[destructors.scope.lifetime-extension.exprs]
357+
297358
For a let statement with an initializer, an *extending expression* is an
298359
expression which is one of the following:
299360

@@ -346,6 +407,8 @@ let x = (&temp()).use_temp(); // ERROR
346407

347408
## Not running destructors
348409

410+
r[destructors.forget]
411+
349412
[`std::mem::forget`] can be used to prevent the destructor of a variable from being run,
350413
and [`std::mem::ManuallyDrop`] provides a wrapper to prevent a
351414
variable or field from being dropped automatically.

0 commit comments

Comments
 (0)