Skip to content

Commit

Permalink
add some test cases from rustc's test suite
Browse files Browse the repository at this point in the history
  • Loading branch information
dnbln committed Nov 19, 2023
1 parent 427cba2 commit fb343f3
Show file tree
Hide file tree
Showing 3 changed files with 733 additions and 16 deletions.
335 changes: 335 additions & 0 deletions tests/ui/needless_move.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
//! any of the `move`s are removed.
#![warn(clippy::needless_move)]
#![allow(unused)]
#![allow(clippy::useless_format)]
#![allow(clippy::let_and_return)]

#[derive(Copy, Clone)]
struct Copy;
Expand Down Expand Up @@ -370,4 +373,336 @@ fn main() {
a.non_copy = NonCopy;
with_owned(a);
});

// below are a few tests from rustc's testsuite that use move closures,
// which might uncover edge cases

// rust/$DIR/closures/2229_closure_analysis/migrations/no_migrations.rs

fn _no_migrations() {
// Set of test cases that don't need migrations

#![deny(rust_2021_incompatible_closure_captures)]

// Copy types as copied by the closure instead of being moved into the closure
// Therefore their drop order isn't tied to the closure and won't be requiring any
// migrations.
fn test1_only_copy_types() {
let t = (0i32, 0i32);

let c = || {
let _t = t.0;
};

c();
}

// Same as test1 but using a move closure
fn test2_only_copy_types_move_closure() {
let t = (0i32, 0i32);

let c = move || {
println!("{}", t.0);
};

c();
}

// Don't need to migrate if captured by ref
fn test3_only_copy_types_move_closure() {
let t = (String::new(), String::new());

let c = || {
println!("{}", t.0);
};

c();
}

// Test migration analysis in case of Insignificant Drop + Non Drop aggregates.
// Note in this test the closure captures a non Drop type and therefore the variable
// is only captured by ref.
fn test4_insignificant_drop_non_drop_aggregate() {
let t = (String::new(), 0i32);

let c = || {
let _t = t.1;
};

c();
}

struct Foo(i32);
impl Drop for Foo {
fn drop(&mut self) {
println!("{:?} dropped", self.0);
}
}

// Test migration analysis in case of Significant Drop + Non Drop aggregates.
// Note in this test the closure captures a non Drop type and therefore the variable
// is only captured by ref.
fn test5_significant_drop_non_drop_aggregate() {
let t = (Foo(0), 0i32);

let c = || {
let _t = t.1;
};

c();
}

fn main() {
test1_only_copy_types();
test2_only_copy_types_move_closure();
test3_only_copy_types_move_closure();
test4_insignificant_drop_non_drop_aggregate();
test5_significant_drop_non_drop_aggregate();
}
}

// rust/$DIR/closures/2229_closure_analysis/run_pass/issue-88476.rs

fn _issue_88476() {
use std::rc::Rc;

// Test that we restrict precision when moving not-`Copy` types, if any of the parent paths
// implement `Drop`. This is to ensure that we don't move out of a type that implements Drop.
pub fn test1() {
struct Foo(Rc<i32>);

impl Drop for Foo {
fn drop(self: &mut Foo) {}
}

let f = Foo(Rc::new(1));
let x = move || {
println!("{:?}", f.0);
};

x();
}

// Test that we don't restrict precision when moving `Copy` types(i.e. when copying),
// even if any of the parent paths implement `Drop`.
pub fn test2() {
struct Character {
hp: u32,
name: String,
}

impl Drop for Character {
fn drop(&mut self) {}
}

let character = Character {
hp: 100,
name: format!("A"),
};

let c = move || println!("{}", character.hp);

c();

println!("{}", character.name);
}

fn main() {}
}

// rust/$DIR/closures/2229_closure_analysis/preserve_field_drop_order2.rs

fn _preserve_field_drop_order2() {
#[derive(Debug)]
struct Dropable(&'static str);

impl Drop for Dropable {
fn drop(&mut self) {
println!("Dropping {}", self.0)
}
}

#[derive(Debug)]
struct A {
x: Dropable,
y: Dropable,
}

#[derive(Debug)]
struct B {
c: A,
d: A,
}

#[derive(Debug)]
struct R<'a> {
c: &'a A,
d: &'a A,
}

fn main() {
let a = A {
x: Dropable("x"),
y: Dropable("y"),
};

let c = move || println!("{:?} {:?}", a.y, a.x);

c();

let b = B {
c: A {
x: Dropable("b.c.x"),
y: Dropable("b.c.y"),
},
d: A {
x: Dropable("b.d.x"),
y: Dropable("b.d.y"),
},
};

let d = move || println!("{:?} {:?} {:?} {:?}", b.d.y, b.d.x, b.c.y, b.c.x);

d();

let r = R {
c: &A {
x: Dropable("r.c.x"),
y: Dropable("r.c.y"),
},
d: &A {
x: Dropable("r.d.x"),
y: Dropable("r.d.y"),
},
};

let e = move || println!("{:?} {:?} {:?} {:?}", r.d.y, r.d.x, r.c.y, r.c.x);

e();
}
}

// rust/$DIR/closures/issue-72408-nested-closures-exponential.rs

fn _issue_72408_nested_closures_exponential() {

/*
// commented out because it takes forever to run with this
// Closures include captured types twice in a type tree.
//
// Wrapping one closure with another leads to doubling
// the amount of types in the type tree.
//
// This test ensures that rust can handle
// deeply nested type trees with a lot
// of duplicated subtrees.
fn dup(f: impl Fn(i32) -> i32) -> impl Fn(i32) -> i32 {
move |a| f(a * 2)
}
fn main() {
let f = |a| a;
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
// Compiler dies around here if it tries
// to walk the tree exhaustively.
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
let f = dup(f);
println!("Type size was at least {}", f(1));
}
*/
}

// rust/$DIR/closures/issue-97607.rs

fn _issue_97607() {
#[allow(unused)]

fn test<T, F, U>(f: F) -> Box<dyn Fn(T) -> U + 'static>
where
F: 'static + Fn(T) -> U,
for<'a> U: 'a, // < This is the problematic line, see #97607
{
Box::new(f)
}

fn main() {}
}

// rust/$DIR/closures/once-move-out-on-heap.rs

fn _once_move_out_on_heap() {
// Testing guarantees provided by once functions.

use std::sync::Arc;

fn foo<F: FnOnce()>(blk: F) {
blk();
}

pub fn main() {
let x = Arc::new(true);
foo(|| {
assert!(*x);
drop(x);
});
}
}

// rust/$DIR/closures/supertrait-hint-references-assoc-ty.rs

fn _supertrait_hint_references_assoc_ty() {
pub trait Fn0: Fn(i32) -> Self::Out {
type Out;
}

impl<F: Fn(i32)> Fn0 for F {
type Out = ();
}

pub fn closure_typer(_: impl Fn0) {}

fn main() {
closure_typer(|x| {
let _: i64 = x.into();
});
}
}
}
Loading

0 comments on commit fb343f3

Please sign in to comment.