Skip to content

Get rid of is_min_const_fn #84547

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Apr 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions compiler/rustc_middle/src/mir/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
49 changes: 0 additions & 49 deletions compiler/rustc_mir/src/const_eval/fn_queries.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -34,54 +33,6 @@ pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
}
}

/// 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 }
Expand Down
67 changes: 17 additions & 50 deletions compiler/rustc_mir/src/transform/check_unsafety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<UnsafetyViolation>,
source_info: SourceInfo,
tcx: TyCtxt<'tcx>,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
)
}
Expand Down Expand Up @@ -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,
),
}
Expand Down Expand Up @@ -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,
)
}
Expand Down Expand Up @@ -258,15 +249,15 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
);
if !nodrop {
self.require_unsafe(
UnsafetyViolationKind::GeneralAndConstFn,
UnsafetyViolationKind::General,
UnsafetyViolationDetails::AssignToDroppingUnionField,
);
} else {
// write to non-drop union field, safe
}
} else {
self.require_unsafe(
UnsafetyViolationKind::GeneralAndConstFn,
UnsafetyViolationKind::General,
UnsafetyViolationDetails::AccessToUnionField,
)
}
Expand All @@ -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
Expand Down Expand Up @@ -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")
}
Expand Down Expand Up @@ -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
}
};
Expand Down Expand Up @@ -394,7 +364,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
} else {
continue;
};
self.require_unsafe(UnsafetyViolationKind::GeneralAndConstFn, details);
self.require_unsafe(UnsafetyViolationKind::General, details);
}
}
}
Expand All @@ -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,
)
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down
14 changes: 4 additions & 10 deletions library/alloc/src/raw_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,11 @@ pub struct RawVec<T, A: Allocator = Global> {
}

impl<T> RawVec<T, Global> {
/// 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<T>::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<T>::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)
Expand Down
3 changes: 1 addition & 2 deletions src/librustdoc/clean/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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| {
Expand Down
4 changes: 2 additions & 2 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -1048,7 +1048,7 @@ impl Clean<Item> 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
Expand Down
22 changes: 18 additions & 4 deletions src/test/ui/cast/cast-ptr-to-int-const.rs
Original file line number Diff line number Diff line change
@@ -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
}
21 changes: 0 additions & 21 deletions src/test/ui/cast/cast-ptr-to-int-const.stderr

This file was deleted.

19 changes: 19 additions & 0 deletions src/test/ui/cast/cast-ptr-to-int-const.with_feature.stderr
Original file line number Diff line number Diff line change
@@ -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`.
Loading