diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 184ed19da9524..1e9dff108ab77 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -128,6 +128,7 @@ #![feature(const_transmute)] #![feature(reverse_bits)] #![feature(non_exhaustive)] +#![cfg_attr(not(stage0), feature(const_write_bytes))] #[prelude_import] #[allow(unused)] diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 27ee9556bd089..e27452f99f342 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1039,6 +1039,19 @@ impl MaybeUninit { /// Note that dropping a `MaybeUninit` will never call `T`'s drop code. /// It is your responsibility to make sure `T` gets dropped if it got initialized. #[unstable(feature = "maybe_uninit", issue = "53491")] + #[rustc_const_unstable(feature = "const_maybe_uninit_zeroed")] + #[cfg(not(stage0))] + pub const fn zeroed() -> MaybeUninit { + let mut u = MaybeUninit::::uninitialized(); + unsafe { + (&mut *u.value as *mut T).write_bytes(0u8, 1); + } + u + } + + #[unstable(feature = "maybe_uninit", issue = "53491")] + #[cfg(stage0)] + /// Ceci n'est pas la documentation pub fn zeroed() -> MaybeUninit { let mut u = MaybeUninit::::uninitialized(); unsafe { diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 5fee49ba2fcf2..92004b71a0a4b 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -157,6 +157,23 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> let dest = self.force_allocation(dest)?; self.copy_op(args[0], dest.into())?; } + "write_bytes" => { + let ptr = self.read_value(args[0])?; + let mplace = self.ref_to_mplace(ptr)?; + let val = self.read_scalar(args[1])?.to_u8()?; + let count = self.read_scalar(args[2])?.to_usize(&self.memory)?; + if mplace.layout.is_zst() || count == 0 { + return Ok(true); + } + if let Some(byte_count) = mplace.layout.size.checked_mul(count, &self.memory) { + self.memory.write_repeat(mplace.ptr, val, byte_count)?; + } else { + return err!(Intrinsic( + format!("Overflowing computing `count * size_of::()` ({} * {}) in {}", + count, mplace.layout.size.bytes(), intrinsic_name), + )); + } + } _ => return Ok(false), } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 17fe78d325cf1..7830f88df23be 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -858,6 +858,19 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } } + "write_bytes" => { + if self.tcx.sess.features_untracked().const_write_bytes { + is_const_fn = true; + } else if self.mode != Mode::Fn { + // Using write_bytes in a const expression requires the feature + // gate. + emit_feature_err( + &self.tcx.sess.parse_sess, "const_write_bytes", + self.span, GateIssue::Language, + &format!("The use of std::ptr::write_bytes() \ + is gated in {}s", self.mode)); + } + } name if name.starts_with("simd_shuffle") => { is_shuffle = true; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index adbe2f9d4393f..d7b72050e906b 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -243,6 +243,9 @@ declare_features! ( // Allows panicking during const eval (produces compile-time errors) (active, const_panic, "1.30.0", Some(51999), None), + // Allows writing repeated bytes to a pointer during const eval. + (active, const_write_bytes, "1.31.0", Some(53491), None), + // Allows using #[prelude_import] on glob `use` items. // // rustc internal diff --git a/src/test/run-pass/const-maybe-init-zeroed.rs b/src/test/run-pass/const-maybe-init-zeroed.rs new file mode 100644 index 0000000000000..5276804357fd1 --- /dev/null +++ b/src/test/run-pass/const-maybe-init-zeroed.rs @@ -0,0 +1,26 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![feature(maybe_uninit, const_maybe_uninit_zeroed)] + +use std::mem; + +fn main() { + const UNIT: mem::MaybeUninit<()> = mem::MaybeUninit::zeroed(); + let bytes: [u8; 0] = unsafe { mem::transmute(UNIT) }; + assert_eq!(bytes, [0u8; 0]); + + const STRING: mem::MaybeUninit = mem::MaybeUninit::zeroed(); + let bytes: [u8; mem::size_of::()] = unsafe { mem::transmute(STRING) }; + assert_eq!(bytes, [0u8; mem::size_of::()]); + + const U8: mem::MaybeUninit = mem::MaybeUninit::zeroed(); + let bytes: [u8; 1] = unsafe { mem::transmute(U8) }; + assert_eq!(bytes, [0u8; 1]); +} diff --git a/src/test/ui/feature-gates/feature-gate-const_write_bytes.rs b/src/test/ui/feature-gates/feature-gate-const_write_bytes.rs new file mode 100644 index 0000000000000..570dc99906474 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-const_write_bytes.rs @@ -0,0 +1,18 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(const_fn, const_let)] + +fn main() {} + +const unsafe fn foo(u: *mut u32) { + std::ptr::write_bytes(u, 0u8, 1); + //~^ ERROR The use of std::ptr::write_bytes() is gated in constant functions (see issue #53491) +} diff --git a/src/test/ui/feature-gates/feature-gate-const_write_bytes.stderr b/src/test/ui/feature-gates/feature-gate-const_write_bytes.stderr new file mode 100644 index 0000000000000..91536a287bd41 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-const_write_bytes.stderr @@ -0,0 +1,11 @@ +error[E0658]: The use of std::ptr::write_bytes() is gated in constant functions (see issue #53491) + --> $DIR/feature-gate-const_write_bytes.rs:16:5 + | +LL | std::ptr::write_bytes(u, 0u8, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(const_write_bytes)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`.