Add tests for super let.
This commit is contained in:
parent
6c3417dd15
commit
ccbef74fc5
2 changed files with 460 additions and 0 deletions
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…
Add table
Add a link
Reference in a new issue