add positive and negative tests for temporary scope shortening FCW
This commit is contained in:
parent
bb624dcb4c
commit
f1fbf1f6ae
5 changed files with 214 additions and 0 deletions
|
|
@ -0,0 +1,12 @@
|
|||
//! The macros that are in `../user-defined-macros.rs`, but external to test diagnostics.
|
||||
//@ edition: 2024
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! wrap {
|
||||
($arg:expr) => { { &$arg } }
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! print_with_internal_wrap {
|
||||
() => { println!("{:?}{}", (), $crate::wrap!(String::new())) }
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
//! Future-compatibility warning test for #145838: make sure we catch all expected breakage.
|
||||
//! Shortening temporaries in the tails of block expressions should warn in Rust 2024, and
|
||||
//! shortening temporaries in the tails of `if` expressions' blocks should warn in all editions.
|
||||
//@ revisions: e2021 e2024
|
||||
//@ [e2021] edition: 2021
|
||||
//@ [e2024] edition: 2024
|
||||
//@ check-pass
|
||||
use std::pin::pin;
|
||||
|
||||
struct Struct { field: () }
|
||||
|
||||
fn cond() -> bool { true }
|
||||
fn temp() {}
|
||||
fn array_temp() -> [(); 1] { [()] }
|
||||
fn tuple_temp() -> ((),) { ((),) }
|
||||
fn struct_temp() -> Struct { Struct { field: () } }
|
||||
fn smart_ptr_temp() -> Box<()> { Box::new(()) }
|
||||
|
||||
const CONST_STRING: String = String::new();
|
||||
static STATIC_UNIT: () = ();
|
||||
|
||||
fn main() {
|
||||
let local = String::new();
|
||||
|
||||
// #145880 doesn't apply here, so this `temp()`'s lifetime is reduced by #145838 in Rust 2024.
|
||||
println!("{:?}{:?}", { &temp() }, ());
|
||||
// TODO: warn in Rust 2024
|
||||
|
||||
// In real-world projects, this breakage typically appeared in `if` expressions with a reference
|
||||
// to a `String` temporary in one branch's tail expression. This is edition-independent since
|
||||
// `if` expressions' blocks are temporary scopes in all editions.
|
||||
println!("{:?}{:?}", (), if cond() { &format!("") } else { "" });
|
||||
// TODO: warn in all editions
|
||||
println!("{:?}{:?}", (), if cond() { &"".to_string() } else { "" });
|
||||
// TODO: warn in all editions
|
||||
println!("{:?}{:?}", (), if cond() { &("string".to_owned() + "string") } else { "" });
|
||||
// TODO: warn in all editions
|
||||
|
||||
// Make sure we catch indexed and dereferenced temporaries.
|
||||
pin!(
|
||||
if cond() {
|
||||
&array_temp()[0]
|
||||
// TODO: warn in all editions
|
||||
} else if cond() {
|
||||
&tuple_temp().0
|
||||
// TODO: warn in all editions
|
||||
} else if cond() {
|
||||
&struct_temp().field
|
||||
// TODO: warn in all editions
|
||||
} else {
|
||||
&*&*smart_ptr_temp()
|
||||
// TODO: warn in all editions
|
||||
}
|
||||
);
|
||||
|
||||
// Test that `super let` extended by parent `super let`s in non-extending blocks are caught.
|
||||
pin!(pin!({ &temp() }));
|
||||
// TODO: warn in Rust 2024
|
||||
|
||||
// We shouldn't warn when lifetime extension applies.
|
||||
let _ = format_args!("{:?}{:?}", { &temp() }, if cond() { &temp() } else { &temp() });
|
||||
let _ = pin!(
|
||||
if cond() {
|
||||
&array_temp()[0]
|
||||
} else if cond() {
|
||||
&tuple_temp().0
|
||||
} else if cond() {
|
||||
&struct_temp().field
|
||||
} else {
|
||||
&*&*smart_ptr_temp()
|
||||
}
|
||||
);
|
||||
let _ = pin!(pin!({ &temp() }));
|
||||
|
||||
// We shouldn't warn when borrowing from non-temporary places.
|
||||
pin!({ &local });
|
||||
pin!({ &STATIC_UNIT });
|
||||
|
||||
// We shouldn't warn for promoted constants.
|
||||
pin!({ &size_of::<()>() });
|
||||
pin!({ &(1 / 1) });
|
||||
pin!({ &mut ([] as [(); 0]) });
|
||||
pin!({ &None::<String> });
|
||||
pin!({ &|| String::new() });
|
||||
|
||||
// But we do warn on these temporaries, since they aren't promoted.
|
||||
pin!({ &(1 / 0) });
|
||||
// TODO: warn in Rust 2024
|
||||
pin!({ &mut [()] });
|
||||
// TODO: warn in Rust 2024
|
||||
pin!({ &Some(String::new()) });
|
||||
// TODO: warn in Rust 2024
|
||||
pin!({ &(|| ())() });
|
||||
// TODO: warn in Rust 2024
|
||||
pin!({ &|| &local });
|
||||
// TODO: warn in Rust 2024
|
||||
pin!({ &CONST_STRING });
|
||||
// TODO: warn in Rust 2024
|
||||
|
||||
// This lint only catches future errors. Future dangling pointers do not produce warnings.
|
||||
pin!({ &raw const *&temp() });
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
//! Test that `macro_extended_temporary_scopes` doesn't warn on non-extended temporaries.
|
||||
//@ edition: 2024
|
||||
#![deny(macro_extended_temporary_scopes)] //~ WARN unknown lint
|
||||
|
||||
fn temp() {}
|
||||
|
||||
fn main() {
|
||||
// Due to #145880, this argument isn't an extending context.
|
||||
println!("{:?}", { &temp() });
|
||||
//~^ ERROR temporary value dropped while borrowed
|
||||
|
||||
// Subexpressions of function call expressions are not extending.
|
||||
println!("{:?}{:?}", (), { std::convert::identity(&temp()) });
|
||||
//~^ ERROR temporary value dropped while borrowed
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
warning: unknown lint: `macro_extended_temporary_scopes`
|
||||
--> $DIR/non-extended.rs:3:9
|
||||
|
|
||||
LL | #![deny(macro_extended_temporary_scopes)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(unknown_lints)]` on by default
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/non-extended.rs:9: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[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/non-extended.rs:13:56
|
||||
|
|
||||
LL | println!("{:?}{:?}", (), { std::convert::identity(&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 2 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0716`.
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
//! Test that the future-compatibility warning for #145838 doesn't break in the presence of
|
||||
//! user-defined macros.
|
||||
//@ build-pass
|
||||
//@ edition: 2024
|
||||
//@ aux-build:external-macros.rs
|
||||
//@ dont-require-annotations: NOTE
|
||||
|
||||
extern crate external_macros;
|
||||
|
||||
macro_rules! wrap {
|
||||
($arg:expr) => { { &$arg } }
|
||||
}
|
||||
|
||||
macro_rules! print_with_internal_wrap {
|
||||
() => { println!("{:?}{}", (), wrap!(String::new())) }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
print!(
|
||||
"{:?}{}",
|
||||
(),
|
||||
format_args!(
|
||||
"{:?}{:?}",
|
||||
|
||||
// This is promoted; do not warn.
|
||||
wrap!(None::<String>),
|
||||
|
||||
// This does not promote; warn.
|
||||
wrap!(String::new())
|
||||
// TODO: warn
|
||||
)
|
||||
);
|
||||
|
||||
print_with_internal_wrap!();
|
||||
// TODO: warn
|
||||
|
||||
print!(
|
||||
"{:?}{:?}",
|
||||
|
||||
// This is promoted; do not warn.
|
||||
external_macros::wrap!(None::<String>),
|
||||
|
||||
// This does not promote; warn.
|
||||
external_macros::wrap!(String::new())
|
||||
// TODO: warn
|
||||
);
|
||||
|
||||
external_macros::print_with_internal_wrap!();
|
||||
// TODO: warn
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue