mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-17 06:26:55 +00:00
Add tests for super let.
This commit is contained in:
parent
6c3417dd15
commit
ccbef74fc5
174
tests/ui/super-let.borrowck.stderr
Normal file
174
tests/ui/super-let.borrowck.stderr
Normal file
@ -0,0 +1,174 @@
|
||||
error[E0506]: cannot assign to `x` because it is borrowed
|
||||
--> $DIR/super-let.rs:30:28
|
||||
|
|
||||
LL | super let b = DropMe(&mut x);
|
||||
| ------ `x` is borrowed here
|
||||
...
|
||||
LL | #[cfg(borrowck)] { x = true; }
|
||||
| ^^^^^^^^ `x` is assigned to here but it was already borrowed
|
||||
...
|
||||
LL | }
|
||||
| - borrow might be used here, when `b` is dropped and runs the `Drop` code for type `DropMe`
|
||||
|
||||
error[E0506]: cannot assign to `x` because it is borrowed
|
||||
--> $DIR/super-let.rs:46:28
|
||||
|
|
||||
LL | super let b = &DropMe(&mut x);
|
||||
| --------------
|
||||
| | |
|
||||
| | `x` is borrowed here
|
||||
| a temporary with access to the borrow is created here ...
|
||||
...
|
||||
LL | #[cfg(borrowck)] { x = true; }
|
||||
| ^^^^^^^^ `x` is assigned to here but it was already borrowed
|
||||
...
|
||||
LL | }
|
||||
| - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DropMe`
|
||||
|
||||
error[E0506]: cannot assign to `x` because it is borrowed
|
||||
--> $DIR/super-let.rs:64:32
|
||||
|
|
||||
LL | super let b = identity(&DropMe(&mut x));
|
||||
| --------------
|
||||
| | |
|
||||
| | `x` is borrowed here
|
||||
| a temporary with access to the borrow is created here ...
|
||||
LL | #[cfg(borrowck)] { x = true; }
|
||||
| ^^^^^^^^ `x` is assigned to here but it was already borrowed
|
||||
...
|
||||
LL | };
|
||||
| - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DropMe`
|
||||
|
||||
error[E0506]: cannot assign to `x` because it is borrowed
|
||||
--> $DIR/super-let.rs:87:36
|
||||
|
|
||||
LL | super let b = identity(&DropMe(&mut x));
|
||||
| --------------
|
||||
| | |
|
||||
| | `x` is borrowed here
|
||||
| a temporary with access to the borrow is created here ...
|
||||
...
|
||||
LL | #[cfg(borrowck)] { x = true; }
|
||||
| ^^^^^^^^ `x` is assigned to here but it was already borrowed
|
||||
...
|
||||
LL | ));
|
||||
| - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DropMe`
|
||||
|
||||
error[E0506]: cannot assign to `x` because it is borrowed
|
||||
--> $DIR/super-let.rs:107:28
|
||||
|
|
||||
LL | super let b = DropMe(&mut x);
|
||||
| ------ `x` is borrowed here
|
||||
...
|
||||
LL | #[cfg(borrowck)] { x = true; }
|
||||
| ^^^^^^^^ `x` is assigned to here but it was already borrowed
|
||||
...
|
||||
LL | }
|
||||
| - borrow might be used here, when `b` is dropped and runs the `Drop` code for type `DropMe`
|
||||
|
||||
error[E0506]: cannot assign to `x` because it is borrowed
|
||||
--> $DIR/super-let.rs:125:28
|
||||
|
|
||||
LL | super let b = DropMe(&mut x);
|
||||
| ------ `x` is borrowed here
|
||||
...
|
||||
LL | #[cfg(borrowck)] { x = true; }
|
||||
| ^^^^^^^^ `x` is assigned to here but it was already borrowed
|
||||
...
|
||||
LL | }
|
||||
| - borrow might be used here, when `b` is dropped and runs the `Drop` code for type `DropMe`
|
||||
|
||||
error[E0506]: cannot assign to `x` because it is borrowed
|
||||
--> $DIR/super-let.rs:143:28
|
||||
|
|
||||
LL | super let b = DropMe(&mut x);
|
||||
| ------ `x` is borrowed here
|
||||
...
|
||||
LL | #[cfg(borrowck)] { x = true; }
|
||||
| ^^^^^^^^ `x` is assigned to here but it was already borrowed
|
||||
...
|
||||
LL | }
|
||||
| - borrow might be used here, when `b` is dropped and runs the `Drop` code for type `DropMe`
|
||||
|
||||
error[E0506]: cannot assign to `x` because it is borrowed
|
||||
--> $DIR/super-let.rs:159:28
|
||||
|
|
||||
LL | b = DropMe(&mut x);
|
||||
| ------ `x` is borrowed here
|
||||
...
|
||||
LL | #[cfg(borrowck)] { x = true; }
|
||||
| ^^^^^^^^ `x` is assigned to here but it was already borrowed
|
||||
LL | drop(a);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/super-let.rs:172:33
|
||||
|
|
||||
LL | #[cfg(borrowck)] { a = &String::from("asdf"); };
|
||||
| ^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
|
||||
| |
|
||||
| creates a temporary value which is freed while still in use
|
||||
...
|
||||
LL | let _ = a;
|
||||
| - borrow later used here
|
||||
|
|
||||
= note: consider using a `let` binding to create a longer lived value
|
||||
|
||||
error[E0506]: cannot assign to `x` because it is borrowed
|
||||
--> $DIR/super-let.rs:206:28
|
||||
|
|
||||
LL | super let d = &DropMe(&mut x);
|
||||
| --------------
|
||||
| | |
|
||||
| | `x` is borrowed here
|
||||
| a temporary with access to the borrow is created here ...
|
||||
...
|
||||
LL | #[cfg(borrowck)] { x = true; }
|
||||
| ^^^^^^^^ `x` is assigned to here but it was already borrowed
|
||||
...
|
||||
LL | }
|
||||
| - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DropMe`
|
||||
|
||||
error[E0506]: cannot assign to `x` because it is borrowed
|
||||
--> $DIR/super-let.rs:227:32
|
||||
|
|
||||
LL | super let d = identity(&DropMe(&mut x));
|
||||
| --------------
|
||||
| | |
|
||||
| | `x` is borrowed here
|
||||
| a temporary with access to the borrow is created here ...
|
||||
...
|
||||
LL | #[cfg(borrowck)] { x = true; }
|
||||
| ^^^^^^^^ `x` is assigned to here but it was already borrowed
|
||||
...
|
||||
LL | };
|
||||
| - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DropMe`
|
||||
|
||||
error[E0506]: cannot assign to `x` because it is borrowed
|
||||
--> $DIR/super-let.rs:246:28
|
||||
|
|
||||
LL | super let b = DropMe(&mut x);
|
||||
| ------ `x` is borrowed here
|
||||
...
|
||||
LL | #[cfg(borrowck)] { x = true; }
|
||||
| ^^^^^^^^ `x` is assigned to here but it was already borrowed
|
||||
...
|
||||
LL | }
|
||||
| - borrow might be used here, when `b` is dropped and runs the `Drop` code for type `DropMe`
|
||||
|
||||
error[E0506]: cannot assign to `x` because it is borrowed
|
||||
--> $DIR/super-let.rs:263:28
|
||||
|
|
||||
LL | let dropme = Some(DropMe(&mut x));
|
||||
| ------ `x` is borrowed here
|
||||
...
|
||||
LL | #[cfg(borrowck)] { x = true; }
|
||||
| ^^^^^^^^ `x` is assigned to here but it was already borrowed
|
||||
...
|
||||
LL | }
|
||||
| - borrow might be used here, when `x` is dropped and runs the `Drop` code for type `DropMe`
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0506, E0716.
|
||||
For more information about an error, try `rustc --explain E0506`.
|
286
tests/ui/super-let.rs
Normal file
286
tests/ui/super-let.rs
Normal file
@ -0,0 +1,286 @@
|
||||
// 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();
|
||||
}
|
Loading…
Reference in New Issue
Block a user