From d23d87cc3e24a89cd84737879a453d6265228582 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 12 Dec 2020 15:48:04 -0800 Subject: [PATCH 1/2] Stop generating code in mem::forget Yes, the optimizer can remove it, but there's really no reason to bother emitting it in the first place. Not to mention that it all gets run in debug mode... --- library/core/src/intrinsics.rs | 7 +++++-- library/core/src/mem/mod.rs | 11 ++++++++++- src/test/codegen/forget-is-nop.rs | 21 +++++++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 src/test/codegen/forget-is-nop.rs diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 5292182269385..b8f08cce8afa9 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -838,8 +838,11 @@ extern "rust-intrinsic" { /// Moves a value out of scope without running drop glue. /// - /// This exists solely for [`mem::forget_unsized`]; normal `forget` uses - /// `ManuallyDrop` instead. + /// This is only strictly needed for [`mem::forget_unsized`]; normal [`mem::forget`] + /// compiles fine just using `ManuallyDrop` instead. + /// + /// As this does literally nothing, it's trivially const-safe. + #[rustc_const_stable(feature = "const_forget_intrinsic", since = "1.50")] pub fn forget(_: T); /// Reinterprets the bits of a value of one type as another type. diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index e84014c68a676..05bc9027b3e4d 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -141,7 +141,16 @@ pub use crate::intrinsics::transmute; #[rustc_const_stable(feature = "const_forget", since = "1.46.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn forget(t: T) { - let _ = ManuallyDrop::new(t); + // Ideally this would just be + // ``` + // let _ = ManuallyDrop::new(t); + // ``` + // but as of 2020-12-12 that actually codegens the construction of the type, + // which there's no reason to do. Please switch it back if things have changed and + // the forget-is-nop codegen test confirms the intrinsic is no longer needed here. + + // SAFETY: Forgetting is safe; it's just the intrinsic that isn't. + unsafe { intrinsics::forget(t) } } /// Like [`forget`], but also accepts unsized values. diff --git a/src/test/codegen/forget-is-nop.rs b/src/test/codegen/forget-is-nop.rs new file mode 100644 index 0000000000000..c6d869ae073b3 --- /dev/null +++ b/src/test/codegen/forget-is-nop.rs @@ -0,0 +1,21 @@ +// compile-flags: -C opt-level=0 + +#![crate_type = "lib"] + +// CHECK-LABEL: mem6forget{{.+}}[100 x %"std::string::String"]* + // CHECK-NOT: alloca + // CHECK-NOT: memcpy + // CHECK: ret + +// CHECK-LABEL: mem6forget{{.+}}[100 x i64]* + // CHECK-NOT: alloca + // CHECK-NOT: memcpy + // CHECK: ret + +pub fn forget_large_copy_type(whatever: [i64; 100]) { + std::mem::forget(whatever) +} + +pub fn forget_large_drop_type(whatever: [String; 100]) { + std::mem::forget(whatever) +} From edb45421398466f73b59a9da45ea8f521adf5fcd Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 13 Dec 2020 21:36:21 -0800 Subject: [PATCH 2/2] Add a test using `mem::forget` in a `const fn` --- library/core/tests/mem.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 268c2ed283f64..54e90387b36e2 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -137,3 +137,16 @@ fn assume_init_good() { assert!(TRUE); } + +#[test] +#[cfg(not(bootstrap))] +fn forget_works_in_const_fn() { + const fn forget_arg_and_return_4(x: Vec) -> i32 { + std::mem::forget(x); + 4 + } + + const FOUR_THE_HARD_WAY: i32 = forget_arg_and_return_4(Vec::new()); + + assert_eq!(FOUR_THE_HARD_WAY, 4); +}