mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-16 05:56:56 +00:00
287 lines
7.2 KiB
Rust
287 lines
7.2 KiB
Rust
// Check in two ways:
|
|
// - borrowck: Check with borrow checking errors when things are alive and dead.
|
|
// - runtime: Check with a mutable bool if things are dropped on time.
|
|
//
|
|
//@ revisions: runtime borrowck
|
|
//@ [runtime] run-pass
|
|
//@ [borrowck] check-fail
|
|
|
|
#![allow(dropping_references)]
|
|
#![feature(super_let, stmt_expr_attributes)]
|
|
|
|
use std::convert::identity;
|
|
|
|
struct DropMe<'a>(&'a mut bool);
|
|
|
|
impl Drop for DropMe<'_> {
|
|
fn drop(&mut self) {
|
|
*self.0 = true;
|
|
}
|
|
}
|
|
|
|
// Check that a super let variable lives as long as the result of a block.
|
|
fn extended_variable() {
|
|
let mut x = false;
|
|
{
|
|
let a = {
|
|
super let b = DropMe(&mut x);
|
|
&b
|
|
};
|
|
#[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
|
|
drop(a);
|
|
// DropMe is still alive here...
|
|
}
|
|
// ... but not here.
|
|
assert_eq!(x, true) // ok
|
|
}
|
|
|
|
// Check that the init expression of a super let is subject to (temporary) lifetime extension.
|
|
fn extended_temporary() {
|
|
let mut x = false;
|
|
{
|
|
let a = {
|
|
super let b = &DropMe(&mut x);
|
|
b
|
|
};
|
|
#[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
|
|
drop(a);
|
|
// DropMe is still alive here...
|
|
}
|
|
// ... but not here.
|
|
assert_eq!(x, true); // ok
|
|
}
|
|
|
|
// Check that even non-extended temporaries live until the end of the block,
|
|
// but (unlike extended temporaries) not beyond that.
|
|
//
|
|
// This is necessary for things like select(pin!(identity(&temp()))) to work.
|
|
fn non_extended() {
|
|
let mut x = false;
|
|
{
|
|
let _a = {
|
|
// Use identity() to supress temporary lifetime extension.
|
|
super let b = identity(&DropMe(&mut x));
|
|
#[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
|
|
b
|
|
// DropMe is still alive here...
|
|
};
|
|
// ... but not here.
|
|
assert_eq!(x, true); // ok
|
|
}
|
|
}
|
|
|
|
// Check that even non-extended temporaries live until the end of the block,
|
|
// but (unlike extended temporaries) not beyond that.
|
|
//
|
|
// This is necessary for things like select(pin!(identity(&temp()))) to work.
|
|
fn non_extended_in_expression() {
|
|
let mut x = false;
|
|
{
|
|
identity((
|
|
{
|
|
// Use identity() to supress temporary lifetime extension.
|
|
super let b = identity(&DropMe(&mut x));
|
|
b
|
|
},
|
|
{
|
|
#[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
|
|
// DropMe is still alive here...
|
|
}
|
|
));
|
|
// ... but not here.
|
|
assert_eq!(x, true); // ok
|
|
}
|
|
}
|
|
|
|
// Check `super let` in a match arm.
|
|
fn match_arm() {
|
|
let mut x = false;
|
|
{
|
|
let a = match Some(123) {
|
|
Some(_) => {
|
|
super let b = DropMe(&mut x);
|
|
&b
|
|
}
|
|
None => unreachable!(),
|
|
};
|
|
#[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
|
|
drop(a);
|
|
// DropMe is still alive here...
|
|
}
|
|
// ... but not here.
|
|
assert_eq!(x, true); // ok
|
|
}
|
|
|
|
// Check `super let` in an if body.
|
|
fn if_body() {
|
|
let mut x = false;
|
|
{
|
|
let a = if true {
|
|
super let b = DropMe(&mut x);
|
|
&b
|
|
} else {
|
|
unreachable!()
|
|
};
|
|
#[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
|
|
drop(a);
|
|
// DropMe is still alive here...
|
|
}
|
|
// ... but not here.
|
|
assert_eq!(x, true); // ok
|
|
}
|
|
|
|
// Check `super let` in an else body.
|
|
fn else_body() {
|
|
let mut x = false;
|
|
{
|
|
let a = if false {
|
|
unreachable!()
|
|
} else {
|
|
super let b = DropMe(&mut x);
|
|
&b
|
|
};
|
|
#[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
|
|
drop(a);
|
|
// DropMe is still alive here...
|
|
}
|
|
// ... but not here.
|
|
assert_eq!(x, true); // ok
|
|
}
|
|
|
|
fn without_initializer() {
|
|
let mut x = false;
|
|
{
|
|
let a = {
|
|
super let b;
|
|
b = DropMe(&mut x);
|
|
b
|
|
};
|
|
#[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
|
|
drop(a);
|
|
// DropMe is still alive here...
|
|
}
|
|
// ... but not here.
|
|
assert_eq!(x, true);
|
|
}
|
|
|
|
// Assignment isn't special, even when assigning to a `super let` variable.
|
|
fn assignment() {
|
|
let mut x = false;
|
|
{
|
|
super let a;
|
|
#[cfg(borrowck)] { a = &String::from("asdf"); }; //[borrowck]~ ERROR dropped while borrowed
|
|
#[cfg(runtime)] { a = drop(&DropMe(&mut x)); } // Temporary dropped at the `;` as usual.
|
|
assert_eq!(x, true);
|
|
let _ = a;
|
|
}
|
|
}
|
|
|
|
// `super let mut` should work just fine.
|
|
fn mutable() {
|
|
let mut x = false;
|
|
{
|
|
let a = {
|
|
super let mut b = None;
|
|
&mut b
|
|
};
|
|
*a = Some(DropMe(&mut x));
|
|
}
|
|
assert_eq!(x, true);
|
|
}
|
|
|
|
// Temporary lifetime extension should recurse through `super let`s.
|
|
fn multiple_levels() {
|
|
let mut x = false;
|
|
{
|
|
let a = {
|
|
super let b = {
|
|
super let c = {
|
|
super let d = &DropMe(&mut x);
|
|
d
|
|
};
|
|
c
|
|
};
|
|
b
|
|
};
|
|
#[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
|
|
drop(a);
|
|
// DropMe is still alive here...
|
|
}
|
|
// ... but not here.
|
|
assert_eq!(x, true);
|
|
}
|
|
|
|
// Non-extended temporaries should be dropped at the
|
|
// end of the first parent statement that isn't `super`.
|
|
fn multiple_levels_but_no_extension() {
|
|
let mut x = false;
|
|
{
|
|
let _a = {
|
|
super let b = {
|
|
super let c = {
|
|
super let d = identity(&DropMe(&mut x));
|
|
d
|
|
};
|
|
c
|
|
};
|
|
#[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
|
|
b
|
|
// DropMe is still alive here...
|
|
};
|
|
// ... but not here.
|
|
assert_eq!(x, true);
|
|
}
|
|
}
|
|
|
|
// Check for potential weird interactions with `let else`.
|
|
fn super_let_and_let_else() {
|
|
let mut x = false;
|
|
{
|
|
let a = 'a: {
|
|
let Some(_) = Some(123) else { unreachable!() };
|
|
super let b = DropMe(&mut x);
|
|
let None = Some(123) else { break 'a &b };
|
|
unreachable!()
|
|
};
|
|
#[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
|
|
// DropMe is still alive here...
|
|
drop(a);
|
|
}
|
|
// ... but not here.
|
|
assert_eq!(x, true);
|
|
}
|
|
|
|
// Check if `super let .. else ..;` works.
|
|
fn super_let_else() {
|
|
let mut x = false;
|
|
{
|
|
let a = {
|
|
let dropme = Some(DropMe(&mut x));
|
|
super let Some(x) = dropme else { unreachable!() };
|
|
&x
|
|
};
|
|
#[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
|
|
// DropMe is still alive here...
|
|
drop(a);
|
|
}
|
|
// ... but not here.
|
|
assert_eq!(x, true);
|
|
}
|
|
|
|
fn main() {
|
|
extended_variable();
|
|
extended_temporary();
|
|
non_extended();
|
|
non_extended_in_expression();
|
|
match_arm();
|
|
if_body();
|
|
else_body();
|
|
without_initializer();
|
|
assignment();
|
|
mutable();
|
|
multiple_levels();
|
|
multiple_levels_but_no_extension();
|
|
super_let_and_let_else();
|
|
super_let_else();
|
|
}
|