cleaned up some tests

This commit is contained in:
Kivooeo
2025-06-03 23:35:08 +05:00
parent aae43c4532
commit 9770f9bb07
9 changed files with 135 additions and 188 deletions
@@ -1,15 +1,19 @@
// Test that the borrow checker prevents pointers to temporaries
// with statement lifetimes from escaping.
//! Test that the borrow checker prevents pointers to temporaries
//! with statement lifetimes from escaping.
use std::ops::Drop;
static mut FLAGS: u64 = 0;
struct StackBox<T> { f: T }
struct AddFlags { bits: u64 }
struct StackBox<T> {
f: T,
}
struct AddFlags {
bits: u64,
}
fn AddFlags(bits: u64) -> AddFlags {
AddFlags { bits: bits }
AddFlags { bits }
}
fn arg(x: &AddFlags) -> &AddFlags {
@@ -1,5 +1,5 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/cleanup-rvalue-scopes-cf.rs:26:19
--> $DIR/rvalue-borrow-scope-error.rs:30:19
|
LL | let x1 = arg(&AddFlags(1));
| ^^^^^^^^^^^ - temporary value is freed at the end of this statement
@@ -16,7 +16,7 @@ LL ~ let x1 = arg(&binding);
|
error[E0716]: temporary value dropped while borrowed
--> $DIR/cleanup-rvalue-scopes-cf.rs:27:14
--> $DIR/rvalue-borrow-scope-error.rs:31:14
|
LL | let x2 = AddFlags(1).get();
| ^^^^^^^^^^^ - temporary value is freed at the end of this statement
@@ -33,7 +33,7 @@ LL ~ let x2 = binding.get();
|
error[E0716]: temporary value dropped while borrowed
--> $DIR/cleanup-rvalue-scopes-cf.rs:28:21
--> $DIR/rvalue-borrow-scope-error.rs:32:21
|
LL | let x3 = &*arg(&AddFlags(1));
| ^^^^^^^^^^^ - temporary value is freed at the end of this statement
@@ -50,7 +50,7 @@ LL ~ let x3 = &*arg(&binding);
|
error[E0716]: temporary value dropped while borrowed
--> $DIR/cleanup-rvalue-scopes-cf.rs:29:24
--> $DIR/rvalue-borrow-scope-error.rs:33:24
|
LL | let ref x4 = *arg(&AddFlags(1));
| ^^^^^^^^^^^ - temporary value is freed at the end of this statement
@@ -67,7 +67,7 @@ LL ~ let ref x4 = *arg(&binding);
|
error[E0716]: temporary value dropped while borrowed
--> $DIR/cleanup-rvalue-scopes-cf.rs:30:24
--> $DIR/rvalue-borrow-scope-error.rs:34:24
|
LL | let &ref x5 = arg(&AddFlags(1));
| ^^^^^^^^^^^ - temporary value is freed at the end of this statement
@@ -84,7 +84,7 @@ LL ~ let &ref x5 = arg(&binding);
|
error[E0716]: temporary value dropped while borrowed
--> $DIR/cleanup-rvalue-scopes-cf.rs:31:14
--> $DIR/rvalue-borrow-scope-error.rs:35:14
|
LL | let x6 = AddFlags(1).get();
| ^^^^^^^^^^^ - temporary value is freed at the end of this statement
@@ -101,7 +101,7 @@ LL ~ let x6 = binding.get();
|
error[E0716]: temporary value dropped while borrowed
--> $DIR/cleanup-rvalue-scopes-cf.rs:32:44
--> $DIR/rvalue-borrow-scope-error.rs:36:44
|
LL | let StackBox { f: x7 } = StackBox { f: AddFlags(1).get() };
| ^^^^^^^^^^^ - temporary value is freed at the end of this statement
-128
View File
@@ -1,128 +0,0 @@
//@ run-pass
#![allow(unused_braces)]
#![allow(non_snake_case)]
#![allow(unused_variables)]
// Test that destructors for rvalue temporaries run either at end of
// statement or end of block, as appropriate given the temporary
// lifetime rules.
#![feature(box_patterns)]
static mut FLAGS: u64 = 0;
struct Box<T> { f: T }
struct AddFlags { bits: u64 }
fn AddFlags(bits: u64) -> AddFlags {
AddFlags { bits: bits }
}
fn arg(exp: u64, _x: &AddFlags) {
check_flags(exp);
}
fn pass<T>(v: T) -> T {
v
}
fn check_flags(exp: u64) {
unsafe {
let x = FLAGS;
FLAGS = 0;
println!("flags {}, expected {}", x, exp);
assert_eq!(x, exp);
}
}
impl AddFlags {
fn check_flags<'a>(&'a self, exp: u64) -> &'a AddFlags {
check_flags(exp);
self
}
fn bits(&self) -> u64 {
self.bits
}
}
impl Drop for AddFlags {
fn drop(&mut self) {
unsafe {
FLAGS = FLAGS + self.bits;
}
}
}
macro_rules! end_of_block {
($pat:pat, $expr:expr) => (
{
println!("end_of_block({})", stringify!({let $pat = $expr;}));
{
// Destructor here does not run until exit from the block.
let $pat = $expr;
check_flags(0);
}
check_flags(1);
}
)
}
macro_rules! end_of_stmt {
($pat:pat, $expr:expr) => (
{
println!("end_of_stmt({})", stringify!($expr));
{
// Destructor here run after `let` statement
// terminates.
let $pat = $expr;
check_flags(1);
}
check_flags(0);
}
)
}
pub fn main() {
// In all these cases, we trip over the rules designed to cover
// the case where we are taking addr of rvalue and storing that
// addr into a stack slot, either via `let ref` or via a `&` in
// the initializer.
end_of_block!(_x, AddFlags(1));
end_of_block!(_x, &AddFlags(1));
end_of_block!(_x, & &AddFlags(1));
end_of_block!(_x, Box { f: AddFlags(1) });
end_of_block!(_x, Box { f: &AddFlags(1) });
end_of_block!(_x, Box { f: &AddFlags(1) });
end_of_block!(_x, pass(AddFlags(1)));
end_of_block!(ref _x, AddFlags(1));
end_of_block!(AddFlags { bits: ref _x }, AddFlags(1));
end_of_block!(&AddFlags { bits }, &AddFlags(1));
end_of_block!((_, ref _y), (AddFlags(1), 22));
end_of_block!(box ref _x, std::boxed::Box::new(AddFlags(1)));
end_of_block!(box _x, std::boxed::Box::new(AddFlags(1)));
end_of_block!(_, { { check_flags(0); &AddFlags(1) } });
end_of_block!(_, &((Box { f: AddFlags(1) }).f));
end_of_block!(_, &(([AddFlags(1)])[0]));
// LHS does not create a ref binding, so temporary lives as long
// as statement, and we do not move the AddFlags out:
end_of_stmt!(_, AddFlags(1));
end_of_stmt!((_, _), (AddFlags(1), 22));
// `&` operator appears inside an arg to a function,
// so it is not prolonged:
end_of_stmt!(ref _x, arg(0, &AddFlags(1)));
// autoref occurs inside receiver, so temp lifetime is not
// prolonged:
end_of_stmt!(ref _x, AddFlags(1).check_flags(0).bits());
// No reference is created on LHS, thus RHS is moved into
// a temporary that lives just as long as the statement.
end_of_stmt!(AddFlags { bits }, AddFlags(1));
}
@@ -1,39 +0,0 @@
//@ run-pass
#![allow(dead_code)]
// If we use GEPi rather than GEP_tup_like when
// storing closure data (as we used to do), the u64 would
// overwrite the u16.
struct Pair<A,B> {
a: A, b: B
}
struct Invoker<A> {
a: A,
b: u16,
}
trait Invokable<A> {
fn f(&self) -> (A, u16);
}
impl<A:Clone> Invokable<A> for Invoker<A> {
fn f(&self) -> (A, u16) {
(self.a.clone(), self.b)
}
}
fn f<A:Clone + 'static>(a: A, b: u16) -> Box<dyn Invokable<A>+'static> {
Box::new(Invoker {
a: a,
b: b,
}) as Box<dyn Invokable<A>+'static>
}
pub fn main() {
let (a, b) = f(22_u64, 44u16).f();
println!("a={} b={}", a, b);
assert_eq!(a, 22u64);
assert_eq!(b, 44u16);
}
@@ -1,4 +1,5 @@
// This test checks the output format without the intermediate json representation
//! This test checks the output format without the intermediate json representation
//@ compile-flags: --error-format=human
pub fn main() {
@@ -1,5 +1,5 @@
error[E0384]: cannot assign twice to immutable variable `x`
--> $DIR/command-line-diagnostics.rs:6:5
--> $DIR/command-line-error-format-human.rs:7:5
|
LL | let x = 42;
| - first assignment to `x`
@@ -1,10 +1,9 @@
//@ run-pass
// Test that cleanups for the RHS of shortcircuiting operators work.
//! Test that cleanups for the RHS of shortcircuiting operators work.
//@ run-pass
#![allow(deref_nullptr)]
use std::env;
pub fn main() {
@@ -18,6 +17,8 @@ pub fn main() {
if args.len() >= 2 && args[1] == "signal" {
// Raise a segfault.
unsafe { *std::ptr::null_mut::<isize>() = 0; }
unsafe {
*std::ptr::null_mut::<isize>() = 0;
}
}
}
@@ -0,0 +1,104 @@
//! Test that destructors for temporaries run either at end of
//! statement or end of block as appropriate.
//@ run-pass
#![feature(box_patterns)]
static mut FLAGS: u64 = 0;
struct Box<T> {
f: T,
}
struct AddFlags {
bits: u64,
}
fn add_flags(bits: u64) -> AddFlags {
AddFlags { bits }
}
fn arg(expected: u64, _x: &AddFlags) {
check_flags(expected);
}
fn pass<T>(v: T) -> T {
v
}
fn check_flags(expected: u64) {
unsafe {
let actual = FLAGS;
FLAGS = 0;
assert_eq!(actual, expected, "flags {}, expected {}", actual, expected);
}
}
impl AddFlags {
fn check_flags(&self, expected: u64) -> &AddFlags {
check_flags(expected);
self
}
fn bits(&self) -> u64 {
self.bits
}
}
impl Drop for AddFlags {
fn drop(&mut self) {
unsafe {
FLAGS += self.bits;
}
}
}
macro_rules! end_of_block {
($pat:pat, $expr:expr) => {{
{
let $pat = $expr;
check_flags(0);
}
check_flags(1);
}};
}
macro_rules! end_of_stmt {
($pat:pat, $expr:expr) => {{
{
let $pat = $expr;
check_flags(1);
}
check_flags(0);
}};
}
fn main() {
end_of_block!(_x, add_flags(1));
end_of_block!(_x, &add_flags(1));
end_of_block!(_x, &&add_flags(1));
end_of_block!(_x, Box { f: add_flags(1) });
end_of_block!(_x, Box { f: &add_flags(1) });
end_of_block!(_x, pass(add_flags(1)));
end_of_block!(ref _x, add_flags(1));
end_of_block!(AddFlags { bits: ref _x }, add_flags(1));
end_of_block!(&AddFlags { bits: _ }, &add_flags(1));
end_of_block!((_, ref _y), (add_flags(1), 22));
end_of_block!(box ref _x, std::boxed::Box::new(add_flags(1)));
end_of_block!(box _x, std::boxed::Box::new(add_flags(1)));
end_of_block!(_, {
{
check_flags(0);
&add_flags(1)
}
});
end_of_block!(_, &((Box { f: add_flags(1) }).f));
end_of_block!(_, &(([add_flags(1)])[0]));
end_of_stmt!(_, add_flags(1));
end_of_stmt!((_, _), (add_flags(1), 22));
end_of_stmt!(ref _x, arg(0, &add_flags(1)));
end_of_stmt!(ref _x, add_flags(1).check_flags(0).bits());
end_of_stmt!(AddFlags { bits: _ }, add_flags(1));
}
@@ -25,16 +25,20 @@
use std::thread;
enum Conzabble {
Bickwick(Foo)
Bickwick(Foo),
}
struct Foo { field: Box<usize> }
struct Foo {
field: Box<usize>,
}
fn do_it(x: &[usize]) -> Foo {
panic!()
}
fn get_bar(x: usize) -> Vec<usize> { vec![x * 2] }
fn get_bar(x: usize) -> Vec<usize> {
vec![x * 2]
}
pub fn fails() {
let x = 2;