Skip to content

Commit 83b98aa

Browse files
committed
Revise extending patterns text
Let's add examples, and let's move to this section two of the examples from extending expressions, as they're actually demonstrations of extending patterns.
1 parent 58b917b commit 83b98aa

File tree

1 file changed

+56
-11
lines changed

1 file changed

+56
-11
lines changed

src/destructors.md

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -408,20 +408,69 @@ r[destructors.scope.lifetime-extension.patterns]
408408
#### Extending based on patterns
409409

410410
r[destructors.scope.lifetime-extension.patterns.extending]
411-
An *extending pattern* is either
411+
An *extending pattern* is either:
412412

413413
* An [identifier pattern] that binds by reference or mutable reference.
414-
* A [struct][struct pattern], [tuple][tuple pattern], [tuple struct][tuple
415-
struct pattern], [slice][slice pattern], or [or-pattern][or-patterns] where at least one of the
416-
direct subpatterns is an extending pattern.
417414

418-
So `ref x`, `V(ref x)` and `[ref x, y]` are all extending patterns, but `x`,
419-
`&ref x` and `&(ref x,)` are not.
415+
```rust
416+
# fn temp() {}
417+
let ref x = temp(); // Binds by reference.
418+
# x;
419+
let ref mut x = temp(); // Binds by mutable reference.
420+
# x;
421+
```
422+
423+
* A [struct][struct pattern], [tuple][tuple pattern], [tuple struct][tuple struct pattern], [slice][slice pattern], or [or-pattern][or-patterns] where at least one of the direct subpatterns is an extending pattern.
424+
425+
```rust
426+
# use core::sync::atomic::{AtomicU64, Ordering::Relaxed};
427+
# static X: AtomicU64 = AtomicU64::new(0);
428+
struct W<T>(T);
429+
# impl<T> Drop for W<T> { fn drop(&mut self) { X.fetch_add(1, Relaxed); } }
430+
let W { 0: ref x } = W(()); // Struct pattern.
431+
# x;
432+
let W(ref x) = W(()); // Tuple struct pattern.
433+
# x;
434+
let (W(ref x),) = (W(()),); // Tuple pattern.
435+
# x;
436+
let [W(ref x), ..] = [W(())]; // Slice pattern.
437+
# x;
438+
let (Ok(W(ref x)) | Err(&ref x)) = Ok(W(())); // Or pattern.
439+
# x;
440+
//
441+
// All of the temporaries above are still live here.
442+
# assert_eq!(0, X.load(Relaxed));
443+
```
444+
445+
So `ref x`, `V(ref x)` and `[ref x, y]` are all extending patterns, but `x`, `&ref x` and `&(ref x,)` are not.
420446

421447
r[destructors.scope.lifetime-extension.patterns.let]
422448
If the pattern in a `let` statement is an extending pattern then the temporary
423449
scope of the initializer expression is extended.
424450

451+
```rust
452+
# fn temp() {}
453+
// This is an extending pattern, so the temporary scope is extended.
454+
let ref x = *&temp(); // OK
455+
# x;
456+
```
457+
458+
```rust,compile_fail,E0716
459+
# fn temp() {}
460+
// This is neither an extending pattern nor an extending expression,
461+
// so the temporary is dropped at the semicolon.
462+
let &ref x = *&&temp(); // ERROR
463+
# x;
464+
```
465+
466+
```rust
467+
# fn temp() {}
468+
// This is not an extending pattern but it is an extending expression,
469+
// so the temporary lives beyond the `let` statement.
470+
let &ref x = &*&temp(); // OK
471+
# x;
472+
```
473+
425474
r[destructors.scope.lifetime-extension.exprs]
426475
#### Extending based on expressions
427476

@@ -479,13 +528,9 @@ let x = if true { &temp() } else { &temp() };
479528
# x;
480529
let x = match () { _ => &temp() }; // `match` arm expression.
481530
# x;
482-
let ref x = temp(); // Initializer expression.
483-
# x;
484-
let ref x = *&temp(); // Initializer expression.
485-
# x;
486531
//
487532
// All of the temporaries above are still live here.
488-
# assert_eq!(X.load(Relaxed), 0);
533+
# assert_eq!(0, X.load(Relaxed));
489534
```
490535

491536
Here are some examples where expressions don't have extended temporary scopes:

0 commit comments

Comments
 (0)