diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index ad3baccf15496..fdd874c6f6822 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -19,10 +19,8 @@ use super::{Field, SourceInfo}; #[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] pub enum UnsafetyViolationKind { - /// Only permitted in regular `fn`s, prohibited in `const fn`s. + /// Unsafe operation outside `unsafe`. General, - /// Permitted both in `const fn`s and regular `fn`s. - GeneralAndConstFn, /// Unsafe operation in an `unsafe fn` but outside an `unsafe` block. /// Has to be handled as a lint for backwards compatibility. UnsafeFn, diff --git a/compiler/rustc_mir/src/const_eval/fn_queries.rs b/compiler/rustc_mir/src/const_eval/fn_queries.rs index 8c18dfcb8d0cc..40419a4d201ac 100644 --- a/compiler/rustc_mir/src/const_eval/fn_queries.rs +++ b/compiler/rustc_mir/src/const_eval/fn_queries.rs @@ -1,4 +1,3 @@ -use rustc_attr as attr; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::hir::map::blocks::FnLikeNode; @@ -34,54 +33,6 @@ pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option { } } -/// Returns `true` if this function must conform to `min_const_fn` -pub fn is_min_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - // Bail out if the signature doesn't contain `const` - if !tcx.is_const_fn_raw(def_id) { - return false; - } - - if tcx.features().staged_api { - // In order for a libstd function to be considered min_const_fn - // it needs to be stable and have no `rustc_const_unstable` attribute. - match tcx.lookup_const_stability(def_id) { - // `rustc_const_unstable` functions don't need to conform. - Some(&attr::ConstStability { ref level, .. }) if level.is_unstable() => false, - None => { - if let Some(stab) = tcx.lookup_stability(def_id) { - if stab.level.is_stable() { - tcx.sess.delay_span_bug( - tcx.def_span(def_id), - "stable const functions must have either `rustc_const_stable` or \ - `rustc_const_unstable` attribute", - ); - // While we errored above, because we don't know if we need to conform, we - // err on the "safe" side and require min_const_fn. - true - } else { - // Unstable functions need not conform to min_const_fn. - false - } - } else { - // Internal functions are forced to conform to min_const_fn. - // Annotate the internal function with a const stability attribute if - // you need to use unstable features. - // Note: this is an arbitrary choice that does not affect stability or const - // safety or anything, it just changes whether we need to annotate some - // internal functions with `rustc_const_stable` or with `rustc_const_unstable` - true - } - } - // Everything else needs to conform, because it would be callable from - // other `min_const_fn` functions. - _ => true, - } - } else { - // users enabling the `const_fn` feature gate can do what they want - !tcx.features().const_fn - } -} - pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { let parent_id = tcx.hir().get_parent_did(hir_id); if !parent_id.is_top_level_module() { is_const_impl_raw(tcx, parent_id) } else { false } diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs index 09da9b2e4d6ff..955be8cc81e18 100644 --- a/compiler/rustc_mir/src/transform/check_unsafety.rs +++ b/compiler/rustc_mir/src/transform/check_unsafety.rs @@ -15,13 +15,10 @@ use rustc_session::lint::Level; use std::ops::Bound; -use crate::const_eval::is_min_const_fn; - pub struct UnsafetyChecker<'a, 'tcx> { body: &'a Body<'tcx>, body_did: LocalDefId, const_context: bool, - min_const_fn: bool, violations: Vec, source_info: SourceInfo, tcx: TyCtxt<'tcx>, @@ -34,21 +31,15 @@ pub struct UnsafetyChecker<'a, 'tcx> { impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { fn new( const_context: bool, - min_const_fn: bool, body: &'a Body<'tcx>, body_did: LocalDefId, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Self { - // sanity check - if min_const_fn { - assert!(const_context); - } Self { body, body_did, const_context, - min_const_fn, violations: vec![], source_info: SourceInfo::outermost(body.span), tcx, @@ -84,7 +75,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { let sig = func_ty.fn_sig(self.tcx); if let hir::Unsafety::Unsafe = sig.unsafety() { self.require_unsafe( - UnsafetyViolationKind::GeneralAndConstFn, + UnsafetyViolationKind::General, UnsafetyViolationDetails::CallToUnsafeFunction, ) } @@ -134,7 +125,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { match self.tcx.layout_scalar_valid_range(def.did) { (Bound::Unbounded, Bound::Unbounded) => {} _ => self.require_unsafe( - UnsafetyViolationKind::GeneralAndConstFn, + UnsafetyViolationKind::General, UnsafetyViolationDetails::InitializingTypeWith, ), } @@ -213,7 +204,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { let base_ty = base.ty(self.body, self.tcx).ty; if base_ty.is_unsafe_ptr() { self.require_unsafe( - UnsafetyViolationKind::GeneralAndConstFn, + UnsafetyViolationKind::General, UnsafetyViolationDetails::DerefOfRawPointer, ) } @@ -258,7 +249,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { ); if !nodrop { self.require_unsafe( - UnsafetyViolationKind::GeneralAndConstFn, + UnsafetyViolationKind::General, UnsafetyViolationDetails::AssignToDroppingUnionField, ); } else { @@ -266,7 +257,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } } else { self.require_unsafe( - UnsafetyViolationKind::GeneralAndConstFn, + UnsafetyViolationKind::General, UnsafetyViolationDetails::AccessToUnionField, ) } @@ -277,6 +268,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { fn require_unsafe(&mut self, kind: UnsafetyViolationKind, details: UnsafetyViolationDetails) { + // Violations can turn out to be `UnsafeFn` during analysis, but they should not start out as such. + assert_ne!(kind, UnsafetyViolationKind::UnsafeFn); + let source_info = self.source_info; let lint_root = self.body.source_scopes[self.source_info.scope] .local_data @@ -304,8 +298,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { Safety::Safe => { for violation in violations { match violation.kind { - UnsafetyViolationKind::GeneralAndConstFn - | UnsafetyViolationKind::General => {} + UnsafetyViolationKind::General => {} UnsafetyViolationKind::UnsafeFn => { bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context") } @@ -334,29 +327,6 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { if !violations.is_empty() { self.used_unsafe.insert(hir_id); } - // only some unsafety is allowed in const fn - if self.min_const_fn { - for violation in violations { - match violation.kind { - // these unsafe things are stable in const fn - UnsafetyViolationKind::GeneralAndConstFn => {} - // these things are forbidden in const fns - UnsafetyViolationKind::General => { - let mut violation = *violation; - // const fns don't need to be backwards compatible and can - // emit these violations as a hard error instead of a backwards - // compat lint - violation.kind = UnsafetyViolationKind::General; - if !self.violations.contains(&violation) { - self.violations.push(violation) - } - } - UnsafetyViolationKind::UnsafeFn => bug!( - "`UnsafetyViolationKind::UnsafeFn` in an `ExplicitUnsafe` context" - ), - } - } - } true } }; @@ -394,7 +364,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { } else { continue; }; - self.require_unsafe(UnsafetyViolationKind::GeneralAndConstFn, details); + self.require_unsafe(UnsafetyViolationKind::General, details); } } } @@ -412,7 +382,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { // Is `callee_features` a subset of `calling_features`? if !callee_features.iter().all(|feature| self_features.contains(feature)) { self.require_unsafe( - UnsafetyViolationKind::GeneralAndConstFn, + UnsafetyViolationKind::General, UnsafetyViolationDetails::CallToFunctionWith, ) } @@ -494,15 +464,12 @@ fn unsafety_check_result<'tcx>( let param_env = tcx.param_env(def.did); let id = tcx.hir().local_def_id_to_hir_id(def.did); - let (const_context, min_const_fn) = match tcx.hir().body_owner_kind(id) { - hir::BodyOwnerKind::Closure => (false, false), - hir::BodyOwnerKind::Fn => { - (tcx.is_const_fn_raw(def.did.to_def_id()), is_min_const_fn(tcx, def.did.to_def_id())) - } - hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => (true, false), + let const_context = match tcx.hir().body_owner_kind(id) { + hir::BodyOwnerKind::Closure => false, + hir::BodyOwnerKind::Fn => tcx.is_const_fn_raw(def.did.to_def_id()), + hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => true, }; - let mut checker = - UnsafetyChecker::new(const_context, min_const_fn, body, def.did, tcx, param_env); + let mut checker = UnsafetyChecker::new(const_context, body, def.did, tcx, param_env); checker.visit_body(&body); check_unused_unsafe(tcx, def.did, &checker.used_unsafe, &mut checker.inherited_blocks); @@ -577,7 +544,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) { if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { " function or" } else { "" }; match kind { - UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => { + UnsafetyViolationKind::General => { // once struct_span_err!( tcx.sess, diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index dc02c9c883ea0..fe87a97bac128 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -53,17 +53,11 @@ pub struct RawVec { } impl RawVec { - /// HACK(Centril): This exists because `#[unstable]` `const fn`s needn't conform - /// to `min_const_fn` and so they cannot be called in `min_const_fn`s either. + /// HACK(Centril): This exists because stable `const fn` can only call stable `const fn`, so + /// they cannot call `Self::new()`. /// - /// If you change `RawVec::new` or dependencies, please take care to not - /// introduce anything that would truly violate `min_const_fn`. - /// - /// NOTE: We could avoid this hack and check conformance with some - /// `#[rustc_force_min_const_fn]` attribute which requires conformance - /// with `min_const_fn` but does not necessarily allow calling it in - /// `stable(...) const fn` / user code not enabling `foo` when - /// `#[rustc_const_unstable(feature = "foo", issue = "01234")]` is present. + /// If you change `RawVec::new` or dependencies, please take care to not introduce anything + /// that would truly const-call something unstable. pub const NEW: Self = Self::new(); /// Creates the biggest possible `RawVec` (on the system heap) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e88a739d04296..3986167bac8d3 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -10,7 +10,6 @@ use rustc_hir::def_id::DefId; use rustc_hir::Mutability; use rustc_metadata::creader::LoadedMacro; use rustc_middle::ty::{self, TyCtxt}; -use rustc_mir::const_eval::is_min_const_fn; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; @@ -210,7 +209,7 @@ fn build_external_function(cx: &mut DocContext<'_>, did: DefId) -> clean::Functi let sig = cx.tcx.fn_sig(did); let constness = - if is_min_const_fn(cx.tcx, did) { hir::Constness::Const } else { hir::Constness::NotConst }; + if cx.tcx.is_const_fn_raw(did) { hir::Constness::Const } else { hir::Constness::NotConst }; let asyncness = cx.tcx.asyncness(did); let predicates = cx.tcx.predicates_of(did); let (generics, decl) = clean::enter_impl_trait(cx, |cx| { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c0a8c88bdeba0..6b04157d9530f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -22,7 +22,7 @@ use rustc_middle::middle::resolve_lifetime as rl; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{self, AdtKind, Lift, Ty, TyCtxt}; -use rustc_mir::const_eval::{is_const_fn, is_min_const_fn, is_unstable_const_fn}; +use rustc_mir::const_eval::{is_const_fn, is_unstable_const_fn}; use rustc_span::hygiene::{AstPass, MacroKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{self, ExpnKind}; @@ -1048,7 +1048,7 @@ impl Clean for ty::AssocItem { ty::TraitContainer(_) => self.defaultness.has_value(), }; if provided { - let constness = if is_min_const_fn(tcx, self.def_id) { + let constness = if tcx.is_const_fn_raw(self.def_id) { hir::Constness::Const } else { hir::Constness::NotConst diff --git a/src/test/ui/cast/cast-ptr-to-int-const.rs b/src/test/ui/cast/cast-ptr-to-int-const.rs index ac153cb57423f..aed099a53eaf4 100644 --- a/src/test/ui/cast/cast-ptr-to-int-const.rs +++ b/src/test/ui/cast/cast-ptr-to-int-const.rs @@ -1,11 +1,25 @@ // gate-test-const_raw_ptr_to_usize_cast +// revisions: with_feature without_feature + +#![cfg_attr(with_feature, feature(const_raw_ptr_to_usize_cast))] fn main() { - const X: u32 = unsafe { - main as u32 //~ ERROR casting pointers to integers in constants is unstable + const X: usize = unsafe { + main as usize //[without_feature]~ ERROR casting pointers to integers in constants is unstable }; const Y: u32 = 0; - const Z: u32 = unsafe { - &Y as *const u32 as u32 //~ ERROR is unstable + const Z: usize = unsafe { + &Y as *const u32 as usize //[without_feature]~ ERROR is unstable + }; + // Cast in `const` without `unsafe` block + const SAFE: usize = { + &Y as *const u32 as usize //[without_feature]~ ERROR is unstable + //[with_feature]~^ ERROR cast of pointer to int is unsafe and requires unsafe }; } + +// Cast in `const fn` without `unsafe` block +const fn test() -> usize { + &0 as *const i32 as usize //[without_feature]~ ERROR is unstable + //[with_feature]~^ ERROR cast of pointer to int is unsafe and requires unsafe +} diff --git a/src/test/ui/cast/cast-ptr-to-int-const.stderr b/src/test/ui/cast/cast-ptr-to-int-const.stderr deleted file mode 100644 index f523b14a98c00..0000000000000 --- a/src/test/ui/cast/cast-ptr-to-int-const.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0658]: casting pointers to integers in constants is unstable - --> $DIR/cast-ptr-to-int-const.rs:5:9 - | -LL | main as u32 - | ^^^^^^^^^^^ - | - = note: see issue #51910 for more information - = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable - -error[E0658]: casting pointers to integers in constants is unstable - --> $DIR/cast-ptr-to-int-const.rs:9:9 - | -LL | &Y as *const u32 as u32 - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #51910 for more information - = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/cast/cast-ptr-to-int-const.with_feature.stderr b/src/test/ui/cast/cast-ptr-to-int-const.with_feature.stderr new file mode 100644 index 0000000000000..8282bc3db0507 --- /dev/null +++ b/src/test/ui/cast/cast-ptr-to-int-const.with_feature.stderr @@ -0,0 +1,19 @@ +error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block + --> $DIR/cast-ptr-to-int-const.rs:16:9 + | +LL | &Y as *const u32 as usize + | ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int + | + = note: casting pointers to integers in constants + +error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block + --> $DIR/cast-ptr-to-int-const.rs:23:5 + | +LL | &0 as *const i32 as usize + | ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int + | + = note: casting pointers to integers in constants + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/cast/cast-ptr-to-int-const.without_feature.stderr b/src/test/ui/cast/cast-ptr-to-int-const.without_feature.stderr new file mode 100644 index 0000000000000..c87fa1a14a4c8 --- /dev/null +++ b/src/test/ui/cast/cast-ptr-to-int-const.without_feature.stderr @@ -0,0 +1,39 @@ +error[E0658]: casting pointers to integers in constants is unstable + --> $DIR/cast-ptr-to-int-const.rs:8:9 + | +LL | main as usize + | ^^^^^^^^^^^^^ + | + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable + +error[E0658]: casting pointers to integers in constants is unstable + --> $DIR/cast-ptr-to-int-const.rs:12:9 + | +LL | &Y as *const u32 as usize + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable + +error[E0658]: casting pointers to integers in constants is unstable + --> $DIR/cast-ptr-to-int-const.rs:16:9 + | +LL | &Y as *const u32 as usize + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable + +error[E0658]: casting pointers to integers in constant functions is unstable + --> $DIR/cast-ptr-to-int-const.rs:23:5 + | +LL | &0 as *const i32 as usize + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index 93b7a897405ae..60425ff853b7e 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { let mir = cx.tcx.optimized_mir(def_id); if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv.as_ref()) { - if rustc_mir::const_eval::is_min_const_fn(cx.tcx, def_id.to_def_id()) { + if cx.tcx.is_const_fn_raw(def_id.to_def_id()) { cx.tcx.sess.span_err(span, &err); } } else {