Skip to content

Commit fb343f3

Browse files
committed
add some test cases from rustc's test suite
1 parent 427cba2 commit fb343f3

File tree

3 files changed

+733
-16
lines changed

3 files changed

+733
-16
lines changed

tests/ui/needless_move.fixed

Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
//! any of the `move`s are removed.
44

55
#![warn(clippy::needless_move)]
6+
#![allow(unused)]
7+
#![allow(clippy::useless_format)]
8+
#![allow(clippy::let_and_return)]
69

710
#[derive(Copy, Clone)]
811
struct Copy;
@@ -370,4 +373,336 @@ fn main() {
370373
a.non_copy = NonCopy;
371374
with_owned(a);
372375
});
376+
377+
// below are a few tests from rustc's testsuite that use move closures,
378+
// which might uncover edge cases
379+
380+
// rust/$DIR/closures/2229_closure_analysis/migrations/no_migrations.rs
381+
382+
fn _no_migrations() {
383+
// Set of test cases that don't need migrations
384+
385+
#![deny(rust_2021_incompatible_closure_captures)]
386+
387+
// Copy types as copied by the closure instead of being moved into the closure
388+
// Therefore their drop order isn't tied to the closure and won't be requiring any
389+
// migrations.
390+
fn test1_only_copy_types() {
391+
let t = (0i32, 0i32);
392+
393+
let c = || {
394+
let _t = t.0;
395+
};
396+
397+
c();
398+
}
399+
400+
// Same as test1 but using a move closure
401+
fn test2_only_copy_types_move_closure() {
402+
let t = (0i32, 0i32);
403+
404+
let c = move || {
405+
println!("{}", t.0);
406+
};
407+
408+
c();
409+
}
410+
411+
// Don't need to migrate if captured by ref
412+
fn test3_only_copy_types_move_closure() {
413+
let t = (String::new(), String::new());
414+
415+
let c = || {
416+
println!("{}", t.0);
417+
};
418+
419+
c();
420+
}
421+
422+
// Test migration analysis in case of Insignificant Drop + Non Drop aggregates.
423+
// Note in this test the closure captures a non Drop type and therefore the variable
424+
// is only captured by ref.
425+
fn test4_insignificant_drop_non_drop_aggregate() {
426+
let t = (String::new(), 0i32);
427+
428+
let c = || {
429+
let _t = t.1;
430+
};
431+
432+
c();
433+
}
434+
435+
struct Foo(i32);
436+
impl Drop for Foo {
437+
fn drop(&mut self) {
438+
println!("{:?} dropped", self.0);
439+
}
440+
}
441+
442+
// Test migration analysis in case of Significant Drop + Non Drop aggregates.
443+
// Note in this test the closure captures a non Drop type and therefore the variable
444+
// is only captured by ref.
445+
fn test5_significant_drop_non_drop_aggregate() {
446+
let t = (Foo(0), 0i32);
447+
448+
let c = || {
449+
let _t = t.1;
450+
};
451+
452+
c();
453+
}
454+
455+
fn main() {
456+
test1_only_copy_types();
457+
test2_only_copy_types_move_closure();
458+
test3_only_copy_types_move_closure();
459+
test4_insignificant_drop_non_drop_aggregate();
460+
test5_significant_drop_non_drop_aggregate();
461+
}
462+
}
463+
464+
// rust/$DIR/closures/2229_closure_analysis/run_pass/issue-88476.rs
465+
466+
fn _issue_88476() {
467+
use std::rc::Rc;
468+
469+
// Test that we restrict precision when moving not-`Copy` types, if any of the parent paths
470+
// implement `Drop`. This is to ensure that we don't move out of a type that implements Drop.
471+
pub fn test1() {
472+
struct Foo(Rc<i32>);
473+
474+
impl Drop for Foo {
475+
fn drop(self: &mut Foo) {}
476+
}
477+
478+
let f = Foo(Rc::new(1));
479+
let x = move || {
480+
println!("{:?}", f.0);
481+
};
482+
483+
x();
484+
}
485+
486+
// Test that we don't restrict precision when moving `Copy` types(i.e. when copying),
487+
// even if any of the parent paths implement `Drop`.
488+
pub fn test2() {
489+
struct Character {
490+
hp: u32,
491+
name: String,
492+
}
493+
494+
impl Drop for Character {
495+
fn drop(&mut self) {}
496+
}
497+
498+
let character = Character {
499+
hp: 100,
500+
name: format!("A"),
501+
};
502+
503+
let c = move || println!("{}", character.hp);
504+
505+
c();
506+
507+
println!("{}", character.name);
508+
}
509+
510+
fn main() {}
511+
}
512+
513+
// rust/$DIR/closures/2229_closure_analysis/preserve_field_drop_order2.rs
514+
515+
fn _preserve_field_drop_order2() {
516+
#[derive(Debug)]
517+
struct Dropable(&'static str);
518+
519+
impl Drop for Dropable {
520+
fn drop(&mut self) {
521+
println!("Dropping {}", self.0)
522+
}
523+
}
524+
525+
#[derive(Debug)]
526+
struct A {
527+
x: Dropable,
528+
y: Dropable,
529+
}
530+
531+
#[derive(Debug)]
532+
struct B {
533+
c: A,
534+
d: A,
535+
}
536+
537+
#[derive(Debug)]
538+
struct R<'a> {
539+
c: &'a A,
540+
d: &'a A,
541+
}
542+
543+
fn main() {
544+
let a = A {
545+
x: Dropable("x"),
546+
y: Dropable("y"),
547+
};
548+
549+
let c = move || println!("{:?} {:?}", a.y, a.x);
550+
551+
c();
552+
553+
let b = B {
554+
c: A {
555+
x: Dropable("b.c.x"),
556+
y: Dropable("b.c.y"),
557+
},
558+
d: A {
559+
x: Dropable("b.d.x"),
560+
y: Dropable("b.d.y"),
561+
},
562+
};
563+
564+
let d = move || println!("{:?} {:?} {:?} {:?}", b.d.y, b.d.x, b.c.y, b.c.x);
565+
566+
d();
567+
568+
let r = R {
569+
c: &A {
570+
x: Dropable("r.c.x"),
571+
y: Dropable("r.c.y"),
572+
},
573+
d: &A {
574+
x: Dropable("r.d.x"),
575+
y: Dropable("r.d.y"),
576+
},
577+
};
578+
579+
let e = move || println!("{:?} {:?} {:?} {:?}", r.d.y, r.d.x, r.c.y, r.c.x);
580+
581+
e();
582+
}
583+
}
584+
585+
// rust/$DIR/closures/issue-72408-nested-closures-exponential.rs
586+
587+
fn _issue_72408_nested_closures_exponential() {
588+
589+
/*
590+
// commented out because it takes forever to run with this
591+
592+
// Closures include captured types twice in a type tree.
593+
//
594+
// Wrapping one closure with another leads to doubling
595+
// the amount of types in the type tree.
596+
//
597+
// This test ensures that rust can handle
598+
// deeply nested type trees with a lot
599+
// of duplicated subtrees.
600+
601+
fn dup(f: impl Fn(i32) -> i32) -> impl Fn(i32) -> i32 {
602+
move |a| f(a * 2)
603+
}
604+
605+
fn main() {
606+
let f = |a| a;
607+
608+
let f = dup(f);
609+
let f = dup(f);
610+
let f = dup(f);
611+
let f = dup(f);
612+
let f = dup(f);
613+
614+
let f = dup(f);
615+
let f = dup(f);
616+
let f = dup(f);
617+
let f = dup(f);
618+
let f = dup(f);
619+
620+
let f = dup(f);
621+
let f = dup(f);
622+
let f = dup(f);
623+
let f = dup(f);
624+
let f = dup(f);
625+
626+
let f = dup(f);
627+
let f = dup(f);
628+
let f = dup(f);
629+
let f = dup(f);
630+
let f = dup(f);
631+
632+
// Compiler dies around here if it tries
633+
// to walk the tree exhaustively.
634+
635+
let f = dup(f);
636+
let f = dup(f);
637+
let f = dup(f);
638+
let f = dup(f);
639+
let f = dup(f);
640+
641+
let f = dup(f);
642+
let f = dup(f);
643+
let f = dup(f);
644+
let f = dup(f);
645+
let f = dup(f);
646+
647+
println!("Type size was at least {}", f(1));
648+
}
649+
650+
*/
651+
}
652+
653+
// rust/$DIR/closures/issue-97607.rs
654+
655+
fn _issue_97607() {
656+
#[allow(unused)]
657+
658+
fn test<T, F, U>(f: F) -> Box<dyn Fn(T) -> U + 'static>
659+
where
660+
F: 'static + Fn(T) -> U,
661+
for<'a> U: 'a, // < This is the problematic line, see #97607
662+
{
663+
Box::new(f)
664+
}
665+
666+
fn main() {}
667+
}
668+
669+
// rust/$DIR/closures/once-move-out-on-heap.rs
670+
671+
fn _once_move_out_on_heap() {
672+
// Testing guarantees provided by once functions.
673+
674+
use std::sync::Arc;
675+
676+
fn foo<F: FnOnce()>(blk: F) {
677+
blk();
678+
}
679+
680+
pub fn main() {
681+
let x = Arc::new(true);
682+
foo(|| {
683+
assert!(*x);
684+
drop(x);
685+
});
686+
}
687+
}
688+
689+
// rust/$DIR/closures/supertrait-hint-references-assoc-ty.rs
690+
691+
fn _supertrait_hint_references_assoc_ty() {
692+
pub trait Fn0: Fn(i32) -> Self::Out {
693+
type Out;
694+
}
695+
696+
impl<F: Fn(i32)> Fn0 for F {
697+
type Out = ();
698+
}
699+
700+
pub fn closure_typer(_: impl Fn0) {}
701+
702+
fn main() {
703+
closure_typer(|x| {
704+
let _: i64 = x.into();
705+
});
706+
}
707+
}
373708
}

0 commit comments

Comments
 (0)