Skip to content

Commit

Permalink
when an intrinsic has a const-stable fallback body, we can easily exp…
Browse files Browse the repository at this point in the history
…ose it on stable
  • Loading branch information
RalfJung committed Nov 4, 2024
1 parent c47cbef commit a6601ae
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 8 deletions.
16 changes: 12 additions & 4 deletions compiler/rustc_const_eval/src/check_consts/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// 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.
Expand All @@ -748,7 +754,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// 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),
Expand All @@ -763,12 +769,14 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
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.
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_middle/src/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1789,8 +1789,7 @@ pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Intrinsi
Some(ty::IntrinsicDef {
name: tcx.item_name(def_id.into()),
must_be_overridden: tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden),
const_stable: tcx.has_attr(def_id, sym::rustc_const_stable_intrinsic)
|| tcx.lookup_const_stability(def_id).is_some_and(|s| s.is_const_stable()),
const_stable: tcx.has_attr(def_id, sym::rustc_const_stable_intrinsic),
})
} else {
None
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/consts/auxiliary/unstable_intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@

#[unstable(feature = "unstable", issue = "42")]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub const unsafe fn size_of_val<T>(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<T>(x: *const T) -> usize { 42 }
12 changes: 12 additions & 0 deletions tests/ui/consts/const-unstable-intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(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<T>(x: *const T) -> usize { 42 }

#[stable(feature = "rust1", since = "1.0.0")]
Expand All @@ -43,10 +45,20 @@ pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize { 42 }
pub const unsafe fn copy<T>(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<T>(src: *const T, dst: *mut T, count: usize) {
unimplemented!()
}

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<T>(src: *const T, _dst: *mut T, _count: usize) {
super::size_of_val(src);
//~^ ERROR cannot be (indirectly) exposed to stable
}
}
12 changes: 10 additions & 2 deletions tests/ui/consts/const-unstable-intrinsic.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`.

0 comments on commit a6601ae

Please sign in to comment.