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/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); +} 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) +}