add tests, some with incorrect lifetime extension behavior
This commit is contained in:
parent
a1dbb44352
commit
9fd57df639
3 changed files with 157 additions and 0 deletions
15
tests/ui/borrowck/format-args-temporary-scopes.e2024.stderr
Normal file
15
tests/ui/borrowck/format-args-temporary-scopes.e2024.stderr
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/format-args-temporary-scopes.rs:13:25
|
||||
|
|
||||
LL | println!("{:?}", { &temp() });
|
||||
| ---^^^^^---
|
||||
| | | |
|
||||
| | | temporary value is freed at the end of this statement
|
||||
| | creates a temporary value which is freed while still in use
|
||||
| borrow later used here
|
||||
|
|
||||
= note: consider using a `let` binding to create a longer lived value
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0716`.
|
||||
20
tests/ui/borrowck/format-args-temporary-scopes.rs
Normal file
20
tests/ui/borrowck/format-args-temporary-scopes.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
//! Test for #145784 as it relates to format arguments: arguments to macros such as `println!`
|
||||
//! should obey normal temporary scoping rules.
|
||||
//@ revisions: e2021 e2024
|
||||
//@ [e2021] check-pass
|
||||
//@ [e2021] edition: 2021
|
||||
//@ [e2024] edition: 2024
|
||||
|
||||
fn temp() {}
|
||||
|
||||
fn main() {
|
||||
// In Rust 2024, block tail expressions are temporary scopes, so the result of `temp()` is
|
||||
// dropped after evaluating `&temp()`.
|
||||
println!("{:?}", { &temp() });
|
||||
//[e2024]~^ ERROR: temporary value dropped while borrowed [E0716]
|
||||
|
||||
// In Rust 1.89, `format_args!` extended the lifetime of all extending expressions in its
|
||||
// arguments when provided with two or more arguments. This caused the result of `temp()` to
|
||||
// outlive the result of the block, making this compile.
|
||||
println!("{:?}{:?}", { &temp() }, ());
|
||||
}
|
||||
122
tests/ui/drop/super-let-tail-expr-drop-order.rs
Normal file
122
tests/ui/drop/super-let-tail-expr-drop-order.rs
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
//! Test for #145784: the argument to `pin!` should be treated as an extending expression if and
|
||||
//! only if the whole `pin!` invocation is an extending expression. Likewise, since `pin!` is
|
||||
//! implemented in terms of `super let`, test the same for `super let` initializers. Since the
|
||||
//! argument to `pin!` and the initializer of `super let` are not temporary drop scopes, this only
|
||||
//! affects lifetimes in two cases:
|
||||
//!
|
||||
//! - Block tail expressions in Rust 2024, which are both extending expressions and temporary drop
|
||||
//! scopes; treating them as extending expressions within a non-extending `pin!` resulted in borrow
|
||||
//! expression operands living past the end of the block.
|
||||
//!
|
||||
//! - Nested `super let` statements, which can have their binding and temporary lifetimes extended
|
||||
//! when the block they're in is an extending expression.
|
||||
//!
|
||||
//! For more information on extending expressions, see
|
||||
//! https://doc.rust-lang.org/reference/destructors.html#extending-based-on-expressions
|
||||
//!
|
||||
//! For tests that `super let` initializers aren't temporary drop scopes, and tests for
|
||||
//! lifetime-extended `super let`, see tests/ui/borrowck/super-let-lifetime-and-drop.rs
|
||||
//@ run-pass
|
||||
//@ revisions: e2021 e2024
|
||||
//@ [e2021] edition: 2021
|
||||
//@ [e2024] edition: 2024
|
||||
|
||||
#![feature(super_let)]
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::pin::pin;
|
||||
|
||||
fn main() {
|
||||
// Test block arguments to `pin!` in non-extending expressions.
|
||||
// In Rust 2021, block tail expressions aren't temporary drop scopes, so their temporaries
|
||||
// should outlive the `pin!` invocation.
|
||||
// In Rust 2024, block tail expressions are temporary drop scopes, so their temporaries should
|
||||
// be dropped after evaluating the tail expression within the `pin!` invocation.
|
||||
// By nesting two `pin!` calls, this ensures non-extended `pin!` doesn't extend an inner `pin!`.
|
||||
assert_drop_order(1..=3, |o| {
|
||||
#[cfg(e2021)]
|
||||
(
|
||||
pin!((
|
||||
pin!({ &o.log(3) as *const LogDrop<'_> }),
|
||||
drop(o.log(1)),
|
||||
)),
|
||||
drop(o.log(2)),
|
||||
);
|
||||
#[cfg(e2024)]
|
||||
(
|
||||
pin!((
|
||||
pin!({ &o.log(3) as *const LogDrop<'_> }),
|
||||
drop(o.log(1)),
|
||||
)),
|
||||
drop(o.log(2)),
|
||||
);
|
||||
});
|
||||
|
||||
// The same holds for `super let` initializers in non-extending expressions.
|
||||
assert_drop_order(1..=4, |o| {
|
||||
#[cfg(e2021)]
|
||||
(
|
||||
{
|
||||
super let _ = {
|
||||
super let _ = { &o.log(4) as *const LogDrop<'_> };
|
||||
drop(o.log(1))
|
||||
};
|
||||
drop(o.log(2))
|
||||
},
|
||||
drop(o.log(3)),
|
||||
);
|
||||
#[cfg(e2024)]
|
||||
(
|
||||
{
|
||||
super let _ = {
|
||||
super let _ = { &o.log(4) as *const LogDrop<'_> };
|
||||
drop(o.log(1))
|
||||
};
|
||||
drop(o.log(2))
|
||||
},
|
||||
drop(o.log(3)),
|
||||
);
|
||||
});
|
||||
|
||||
// Within an extending expression, the argument to `pin!` is also an extending expression,
|
||||
// allowing borrow operands in block tail expressions to have extended lifetimes.
|
||||
assert_drop_order(1..=2, |o| {
|
||||
let _ = pin!({ &o.log(2) as *const LogDrop<'_> });
|
||||
drop(o.log(1));
|
||||
});
|
||||
|
||||
// The same holds for `super let` initializers in extending expressions.
|
||||
assert_drop_order(1..=2, |o| {
|
||||
let _ = { super let _ = { &o.log(2) as *const LogDrop<'_> }; };
|
||||
drop(o.log(1));
|
||||
});
|
||||
}
|
||||
|
||||
// # Test scaffolding...
|
||||
|
||||
struct DropOrder(RefCell<Vec<u64>>);
|
||||
struct LogDrop<'o>(&'o DropOrder, u64);
|
||||
|
||||
impl DropOrder {
|
||||
fn log(&self, n: u64) -> LogDrop<'_> {
|
||||
LogDrop(self, n)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'o> Drop for LogDrop<'o> {
|
||||
fn drop(&mut self) {
|
||||
self.0.0.borrow_mut().push(self.1);
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn assert_drop_order(
|
||||
ex: impl IntoIterator<Item = u64>,
|
||||
f: impl Fn(&DropOrder),
|
||||
) {
|
||||
let order = DropOrder(RefCell::new(Vec::new()));
|
||||
f(&order);
|
||||
let order = order.0.into_inner();
|
||||
let expected: Vec<u64> = ex.into_iter().collect();
|
||||
assert_eq!(order, expected);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue