Skip to content

Commit bcb96fb

Browse files
authored
Merge pull request #1975 from theemathas/patch-2
Or-patterns are extending
2 parents 4984678 + 83b98aa commit bcb96fb

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], or [slice][slice pattern] pattern 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)