Auto merge of #121346 - m-ou-se:temp-lifetime-if-else-match, r=compiler-errors

Propagate temporary lifetime extension into if and match.

This PR makes this work:

```rust
let a = if true {
    ..;
    &temp() // used to error, but now gets lifetime extended
} else {
    ..;
    &temp() // used to error, but now gets lifetime extended
};
```

and

```rust
let a = match () {
    _ => {
        ..;
        &temp() // used to error, but now gets lifetime extended
    }
};
```

to make it consistent with:

```rust
let a = {
    ..;
    &temp() // lifetime is extended
};
```

This is one small part of [the temporary lifetimes work](https://github.com/rust-lang/lang-team/issues/253).

This part is backwards compatible (so doesn't need be edition-gated), because all code affected by this change previously resulted in a hard error.
This commit is contained in:
bors 2024-04-10 18:52:51 +00:00
commit b3bd7058c1
4 changed files with 119 additions and 115 deletions

View File

@ -689,6 +689,8 @@ fn resolve_local<'tcx>(
/// | [ ..., E&, ... ]
/// | ( ..., E&, ... )
/// | {...; E&}
/// | if _ { ...; E& } else { ...; E& }
/// | match _ { ..., _ => E&, ... }
/// | box E&
/// | E& as ...
/// | ( E& )
@ -727,6 +729,17 @@ fn resolve_local<'tcx>(
record_rvalue_scope_if_borrow_expr(visitor, subexpr, blk_id);
}
}
hir::ExprKind::If(_, then_block, else_block) => {
record_rvalue_scope_if_borrow_expr(visitor, then_block, blk_id);
if let Some(else_block) = else_block {
record_rvalue_scope_if_borrow_expr(visitor, else_block, blk_id);
}
}
hir::ExprKind::Match(_, arms, _) => {
for arm in arms {
record_rvalue_scope_if_borrow_expr(visitor, arm.body, blk_id);
}
}
hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) => {
// FIXME(@dingxiangfei2009): choose call arguments here
// for candidacy for extended parameter rule application

View File

@ -7,8 +7,9 @@ fn let_underscore(string: &Option<&str>, mut num: Option<i32>) {
*s += 1;
s
} else {
&mut 0
//~^ ERROR temporary value dropped while borrowed
let a = 0;
&a
//~^ ERROR does not live long enough
};
let _ = if let Some(ref s) = num { s } else { &0 };
let _ = if let Some(mut s) = num {
@ -21,8 +22,9 @@ fn let_underscore(string: &Option<&str>, mut num: Option<i32>) {
*s += 1;
s
} else {
&mut 0
//~^ ERROR temporary value dropped while borrowed
let a = 0;
&a
//~^ ERROR does not live long enough
};
}
@ -33,8 +35,9 @@ fn let_ascribe(string: &Option<&str>, mut num: Option<i32>) {
*s += 1;
s
} else {
&mut 0
//~^ ERROR temporary value dropped while borrowed
let a = 0;
&a
//~^ ERROR does not live long enough
};
let _: _ = if let Some(ref s) = num { s } else { &0 };
let _: _ = if let Some(mut s) = num {
@ -47,8 +50,9 @@ fn let_ascribe(string: &Option<&str>, mut num: Option<i32>) {
*s += 1;
s
} else {
&mut 0
//~^ ERROR temporary value dropped while borrowed
let a = 0;
&a
//~^ ERROR does not live long enough
};
}
@ -63,8 +67,9 @@ fn matched(string: &Option<&str>, mut num: Option<i32>) {
*s += 1;
s
} else {
&mut 0
//~^ ERROR temporary value dropped while borrowed
let a = 0;
&a
//~^ ERROR does not live long enough
} {
_ => {}
};
@ -83,8 +88,9 @@ fn matched(string: &Option<&str>, mut num: Option<i32>) {
*s += 1;
s
} else {
&mut 0
//~^ ERROR temporary value dropped while borrowed
let a = 0;
&a
//~^ ERROR does not live long enough
} {
_ => {}
};

View File

@ -1,117 +1,69 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/let_underscore_temporary.rs:10:14
error[E0597]: `a` does not live long enough
--> $DIR/let_underscore_temporary.rs:11:9
|
LL | let _ = if let Some(s) = &mut num {
| _____________-
LL | | *s += 1;
LL | | s
LL | | } else {
LL | | &mut 0
| | ^ creates a temporary value which is freed while still in use
LL | |
LL | | };
| | -
| | |
| |_____temporary value is freed at the end of this statement
| borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
LL | let a = 0;
| - binding `a` declared here
LL | &a
| ^^ borrowed value does not live long enough
LL |
LL | };
| - `a` dropped here while still borrowed
error[E0716]: temporary value dropped while borrowed
--> $DIR/let_underscore_temporary.rs:24:14
error[E0597]: `a` does not live long enough
--> $DIR/let_underscore_temporary.rs:26:9
|
LL | let _ = if let Some(ref mut s) = num {
| _____________-
LL | | *s += 1;
LL | | s
LL | | } else {
LL | | &mut 0
| | ^ creates a temporary value which is freed while still in use
LL | |
LL | | };
| | -
| | |
| |_____temporary value is freed at the end of this statement
| borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
LL | let a = 0;
| - binding `a` declared here
LL | &a
| ^^ borrowed value does not live long enough
LL |
LL | };
| - `a` dropped here while still borrowed
error[E0716]: temporary value dropped while borrowed
--> $DIR/let_underscore_temporary.rs:36:14
error[E0597]: `a` does not live long enough
--> $DIR/let_underscore_temporary.rs:39:9
|
LL | let _: _ = if let Some(s) = &mut num {
| ________________-
LL | | *s += 1;
LL | | s
LL | | } else {
LL | | &mut 0
| | ^ creates a temporary value which is freed while still in use
LL | |
LL | | };
| | -
| | |
| |_____temporary value is freed at the end of this statement
| borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
LL | let a = 0;
| - binding `a` declared here
LL | &a
| ^^ borrowed value does not live long enough
LL |
LL | };
| - `a` dropped here while still borrowed
error[E0716]: temporary value dropped while borrowed
--> $DIR/let_underscore_temporary.rs:50:14
error[E0597]: `a` does not live long enough
--> $DIR/let_underscore_temporary.rs:54:9
|
LL | let _: _ = if let Some(ref mut s) = num {
| ________________-
LL | | *s += 1;
LL | | s
LL | | } else {
LL | | &mut 0
| | ^ creates a temporary value which is freed while still in use
LL | |
LL | | };
| | -
| | |
| |_____temporary value is freed at the end of this statement
| borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
LL | let a = 0;
| - binding `a` declared here
LL | &a
| ^^ borrowed value does not live long enough
LL |
LL | };
| - `a` dropped here while still borrowed
error[E0716]: temporary value dropped while borrowed
--> $DIR/let_underscore_temporary.rs:66:14
error[E0597]: `a` does not live long enough
--> $DIR/let_underscore_temporary.rs:71:9
|
LL | match if let Some(s) = &mut num {
| ___________-
LL | | *s += 1;
LL | | s
LL | | } else {
LL | | &mut 0
| | ^ creates a temporary value which is freed while still in use
LL | |
LL | | } {
| | -
| | |
| |_____temporary value is freed at the end of this statement
| borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
LL | let a = 0;
| - binding `a` declared here
LL | &a
| ^^ borrowed value does not live long enough
LL |
LL | } {
| - `a` dropped here while still borrowed
error[E0716]: temporary value dropped while borrowed
--> $DIR/let_underscore_temporary.rs:86:14
error[E0597]: `a` does not live long enough
--> $DIR/let_underscore_temporary.rs:92:9
|
LL | match if let Some(ref mut s) = num {
| ___________-
LL | | *s += 1;
LL | | s
LL | | } else {
LL | | &mut 0
| | ^ creates a temporary value which is freed while still in use
LL | |
LL | | } {
| | -
| | |
| |_____temporary value is freed at the end of this statement
| borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
LL | let a = 0;
| - binding `a` declared here
LL | &a
| ^^ borrowed value does not live long enough
LL |
LL | } {
| - `a` dropped here while still borrowed
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0716`.
For more information about this error, try `rustc --explain E0597`.

View File

@ -0,0 +1,33 @@
//@ check-pass
fn temp() -> (String, i32) {
(String::from("Hello"), 1)
}
fn main() {
let a = &temp();
let b = [(&temp(),)];
let c = &temp().0;
let d = &temp().0[..];
let e = {
let _ = 123;
&(*temp().0)[..]
};
let f = if true {
&temp()
} else {
&temp()
};
let g = match true {
true => &temp(),
false => {
let _ = 123;
&temp()
}
};
let h = match temp() {
// The {} moves the value, making a new temporary.
owned_non_temporary => &{ owned_non_temporary },
};
println!("{a:?} {b:?} {c:?} {d:?} {e:?} {f:?} {g:?} {h:?}");
}