From a741b33c145a5f1fa3e7f42a4488750ce8719d4f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Nov 2024 08:49:49 +0100 Subject: [PATCH] when an intrinsic has a const-stable fallback body, we can easily expose it on stable --- .../rustc_const_eval/src/check_consts/check.rs | 16 ++++++++++++---- compiler/rustc_middle/src/ty/util.rs | 3 +-- tests/ui/consts/auxiliary/unstable_intrinsic.rs | 2 ++ tests/ui/consts/const-unstable-intrinsic.rs | 12 ++++++++++++ tests/ui/consts/const-unstable-intrinsic.stderr | 12 ++++++++++-- 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 1c17421e782..aea3d5bd3e7 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -739,6 +739,12 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location // We use `intrinsic.const_stable` to determine if this can be safely exposed to // stable code, rather than `const_stable_indirect`. This is to make // `#[rustc_const_stable_indirect]` an attribute that is always safe to add. + // We also ask is_safe_to_expose_on_stable_const_fn; this determines whether the intrinsic + // fallback body is safe to expose on stable. + let is_const_stable = intrinsic.const_stable + || (!intrinsic.must_be_overridden + && tcx.is_const_fn(callee) + && is_safe_to_expose_on_stable_const_fn(tcx, callee)); match tcx.lookup_const_stability(callee) { None => { // Non-const intrinsic. @@ -748,7 +754,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location // Intrinsic does not need a separate feature gate (we rely on the // regular stability checker). However, we have to worry about recursive // const stability. - if !intrinsic.const_stable && self.enforce_recursive_const_stability() { + if !is_const_stable && self.enforce_recursive_const_stability() { self.dcx().emit_err(errors::UnmarkedIntrinsicExposed { span: self.span, def_path: self.tcx.def_path_str(callee), @@ -763,12 +769,14 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location self.check_op(ops::IntrinsicUnstable { name: intrinsic.name, feature, - const_stable: intrinsic.const_stable, + const_stable: is_const_stable, }); } Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => { - // All good. But ensure this is indeed a const-stable intrinsic. - assert!(intrinsic.const_stable); + // All good. Note that a `#[rustc_const_stable]` intrinsic (meaning it + // can be *directly* invoked from stable const code) does not always + // have the `#[rustc_const_stable_intrinsic]` attribute (which controls + // exposing an intrinsic indirectly); we accept this call anyway. } } // This completes the checks for intrinsics. diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index b5811824683..6ffd149ef14 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1789,8 +1789,7 @@ pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option(x: *const T) -> usize { 42 } #[unstable(feature = "unstable", issue = "42")] #[rustc_const_unstable(feature = "unstable", issue = "42")] #[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] pub const unsafe fn min_align_of_val(x: *const T) -> usize { 42 } diff --git a/tests/ui/consts/const-unstable-intrinsic.rs b/tests/ui/consts/const-unstable-intrinsic.rs index fbe491e0671..56b552b6a3f 100644 --- a/tests/ui/consts/const-unstable-intrinsic.rs +++ b/tests/ui/consts/const-unstable-intrinsic.rs @@ -30,11 +30,13 @@ const fn const_main() { #[unstable(feature = "local", issue = "42")] #[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } #[unstable(feature = "local", issue = "42")] #[rustc_const_unstable(feature = "local", issue = "42")] #[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] pub const unsafe fn min_align_of_val(x: *const T) -> usize { 42 } #[stable(feature = "rust1", since = "1.0.0")] @@ -43,6 +45,7 @@ const fn const_main() { pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { // Const stability attributes are not inherited from parent items. #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { unimplemented!() } @@ -50,3 +53,12 @@ const fn const_main() { unsafe { copy(src, dst, count) } //~^ ERROR cannot be (indirectly) exposed to stable } + +// Ensure that a fallback body is recursively-const-checked. +mod fallback { + #[rustc_intrinsic] + const unsafe fn copy(src: *const T, _dst: *mut T, _count: usize) { + super::size_of_val(src); + //~^ ERROR cannot be (indirectly) exposed to stable + } +} diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr index 2cf76732cf2..3e605f3d003 100644 --- a/tests/ui/consts/const-unstable-intrinsic.stderr +++ b/tests/ui/consts/const-unstable-intrinsic.stderr @@ -60,13 +60,21 @@ LL | const fn const_main() { | error: intrinsic `copy::copy` cannot be (indirectly) exposed to stable - --> $DIR/const-unstable-intrinsic.rs:50:14 + --> $DIR/const-unstable-intrinsic.rs:53:14 | LL | unsafe { copy(src, dst, count) } | ^^^^^^^^^^^^^^^^^^^^^ | = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval) -error: aborting due to 7 previous errors +error: intrinsic `size_of_val` cannot be (indirectly) exposed to stable + --> $DIR/const-unstable-intrinsic.rs:61:9 + | +LL | super::size_of_val(src); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval) + +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0658`.