|
3 | 3 | //! any of the `move`s are removed.
|
4 | 4 |
|
5 | 5 | #![warn(clippy::needless_move)]
|
| 6 | +#![allow(unused)] |
| 7 | +#![allow(clippy::useless_format)] |
| 8 | +#![allow(clippy::let_and_return)] |
6 | 9 |
|
7 | 10 | #[derive(Copy, Clone)]
|
8 | 11 | struct Copy;
|
@@ -370,4 +373,336 @@ fn main() {
|
370 | 373 | a.non_copy = NonCopy;
|
371 | 374 | with_owned(a);
|
372 | 375 | });
|
| 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 | + } |
373 | 708 | }
|
0 commit comments