unsafety checking: no longer care about is_min_const_fn
Rejecting the forbidden unsafe ops is done by const checking, not by unsafety checking
This commit is contained in:
parent
5da10c0121
commit
9082078a26
@ -19,10 +19,8 @@ use super::{Field, SourceInfo};
|
|||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
|
#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
|
||||||
pub enum UnsafetyViolationKind {
|
pub enum UnsafetyViolationKind {
|
||||||
/// Only permitted in regular `fn`s, prohibited in `const fn`s.
|
/// Unsafe operation outside `unsafe`
|
||||||
General,
|
General,
|
||||||
/// Permitted both in `const fn`s and regular `fn`s.
|
|
||||||
GeneralAndConstFn,
|
|
||||||
/// Unsafe operation in an `unsafe fn` but outside an `unsafe` block.
|
/// Unsafe operation in an `unsafe fn` but outside an `unsafe` block.
|
||||||
/// Has to be handled as a lint for backwards compatibility.
|
/// Has to be handled as a lint for backwards compatibility.
|
||||||
UnsafeFn,
|
UnsafeFn,
|
||||||
|
@ -15,13 +15,10 @@ use rustc_session::lint::Level;
|
|||||||
|
|
||||||
use std::ops::Bound;
|
use std::ops::Bound;
|
||||||
|
|
||||||
use crate::const_eval::is_min_const_fn;
|
|
||||||
|
|
||||||
pub struct UnsafetyChecker<'a, 'tcx> {
|
pub struct UnsafetyChecker<'a, 'tcx> {
|
||||||
body: &'a Body<'tcx>,
|
body: &'a Body<'tcx>,
|
||||||
body_did: LocalDefId,
|
body_did: LocalDefId,
|
||||||
const_context: bool,
|
const_context: bool,
|
||||||
min_const_fn: bool,
|
|
||||||
violations: Vec<UnsafetyViolation>,
|
violations: Vec<UnsafetyViolation>,
|
||||||
source_info: SourceInfo,
|
source_info: SourceInfo,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
@ -34,21 +31,15 @@ pub struct UnsafetyChecker<'a, 'tcx> {
|
|||||||
impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
||||||
fn new(
|
fn new(
|
||||||
const_context: bool,
|
const_context: bool,
|
||||||
min_const_fn: bool,
|
|
||||||
body: &'a Body<'tcx>,
|
body: &'a Body<'tcx>,
|
||||||
body_did: LocalDefId,
|
body_did: LocalDefId,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// sanity check
|
|
||||||
if min_const_fn {
|
|
||||||
assert!(const_context);
|
|
||||||
}
|
|
||||||
Self {
|
Self {
|
||||||
body,
|
body,
|
||||||
body_did,
|
body_did,
|
||||||
const_context,
|
const_context,
|
||||||
min_const_fn,
|
|
||||||
violations: vec![],
|
violations: vec![],
|
||||||
source_info: SourceInfo::outermost(body.span),
|
source_info: SourceInfo::outermost(body.span),
|
||||||
tcx,
|
tcx,
|
||||||
@ -84,7 +75,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
|||||||
let sig = func_ty.fn_sig(self.tcx);
|
let sig = func_ty.fn_sig(self.tcx);
|
||||||
if let hir::Unsafety::Unsafe = sig.unsafety() {
|
if let hir::Unsafety::Unsafe = sig.unsafety() {
|
||||||
self.require_unsafe(
|
self.require_unsafe(
|
||||||
UnsafetyViolationKind::GeneralAndConstFn,
|
UnsafetyViolationKind::General,
|
||||||
UnsafetyViolationDetails::CallToUnsafeFunction,
|
UnsafetyViolationDetails::CallToUnsafeFunction,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -134,7 +125,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
|||||||
match self.tcx.layout_scalar_valid_range(def.did) {
|
match self.tcx.layout_scalar_valid_range(def.did) {
|
||||||
(Bound::Unbounded, Bound::Unbounded) => {}
|
(Bound::Unbounded, Bound::Unbounded) => {}
|
||||||
_ => self.require_unsafe(
|
_ => self.require_unsafe(
|
||||||
UnsafetyViolationKind::GeneralAndConstFn,
|
UnsafetyViolationKind::General,
|
||||||
UnsafetyViolationDetails::InitializingTypeWith,
|
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;
|
let base_ty = base.ty(self.body, self.tcx).ty;
|
||||||
if base_ty.is_unsafe_ptr() {
|
if base_ty.is_unsafe_ptr() {
|
||||||
self.require_unsafe(
|
self.require_unsafe(
|
||||||
UnsafetyViolationKind::GeneralAndConstFn,
|
UnsafetyViolationKind::General,
|
||||||
UnsafetyViolationDetails::DerefOfRawPointer,
|
UnsafetyViolationDetails::DerefOfRawPointer,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -258,7 +249,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
|||||||
);
|
);
|
||||||
if !nodrop {
|
if !nodrop {
|
||||||
self.require_unsafe(
|
self.require_unsafe(
|
||||||
UnsafetyViolationKind::GeneralAndConstFn,
|
UnsafetyViolationKind::General,
|
||||||
UnsafetyViolationDetails::AssignToDroppingUnionField,
|
UnsafetyViolationDetails::AssignToDroppingUnionField,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -266,7 +257,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.require_unsafe(
|
self.require_unsafe(
|
||||||
UnsafetyViolationKind::GeneralAndConstFn,
|
UnsafetyViolationKind::General,
|
||||||
UnsafetyViolationDetails::AccessToUnionField,
|
UnsafetyViolationDetails::AccessToUnionField,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -277,6 +268,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
|||||||
|
|
||||||
impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
||||||
fn require_unsafe(&mut self, kind: UnsafetyViolationKind, details: UnsafetyViolationDetails) {
|
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 source_info = self.source_info;
|
||||||
let lint_root = self.body.source_scopes[self.source_info.scope]
|
let lint_root = self.body.source_scopes[self.source_info.scope]
|
||||||
.local_data
|
.local_data
|
||||||
@ -304,8 +298,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
|||||||
Safety::Safe => {
|
Safety::Safe => {
|
||||||
for violation in violations {
|
for violation in violations {
|
||||||
match violation.kind {
|
match violation.kind {
|
||||||
UnsafetyViolationKind::GeneralAndConstFn
|
UnsafetyViolationKind::General => {}
|
||||||
| UnsafetyViolationKind::General => {}
|
|
||||||
UnsafetyViolationKind::UnsafeFn => {
|
UnsafetyViolationKind::UnsafeFn => {
|
||||||
bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context")
|
bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context")
|
||||||
}
|
}
|
||||||
@ -334,29 +327,6 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
|||||||
if !violations.is_empty() {
|
if !violations.is_empty() {
|
||||||
self.used_unsafe.insert(hir_id);
|
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
|
true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -394,7 +364,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
|||||||
} else {
|
} else {
|
||||||
continue;
|
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`?
|
// Is `callee_features` a subset of `calling_features`?
|
||||||
if !callee_features.iter().all(|feature| self_features.contains(feature)) {
|
if !callee_features.iter().all(|feature| self_features.contains(feature)) {
|
||||||
self.require_unsafe(
|
self.require_unsafe(
|
||||||
UnsafetyViolationKind::GeneralAndConstFn,
|
UnsafetyViolationKind::General,
|
||||||
UnsafetyViolationDetails::CallToFunctionWith,
|
UnsafetyViolationDetails::CallToFunctionWith,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -494,15 +464,12 @@ fn unsafety_check_result<'tcx>(
|
|||||||
let param_env = tcx.param_env(def.did);
|
let param_env = tcx.param_env(def.did);
|
||||||
|
|
||||||
let id = tcx.hir().local_def_id_to_hir_id(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) {
|
let const_context = match tcx.hir().body_owner_kind(id) {
|
||||||
hir::BodyOwnerKind::Closure => (false, false),
|
hir::BodyOwnerKind::Closure => false,
|
||||||
hir::BodyOwnerKind::Fn => {
|
hir::BodyOwnerKind::Fn => tcx.is_const_fn_raw(def.did.to_def_id()),
|
||||||
(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,
|
||||||
}
|
|
||||||
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => (true, false),
|
|
||||||
};
|
};
|
||||||
let mut checker =
|
let mut checker = UnsafetyChecker::new(const_context, body, def.did, tcx, param_env);
|
||||||
UnsafetyChecker::new(const_context, min_const_fn, body, def.did, tcx, param_env);
|
|
||||||
checker.visit_body(&body);
|
checker.visit_body(&body);
|
||||||
|
|
||||||
check_unused_unsafe(tcx, def.did, &checker.used_unsafe, &mut checker.inherited_blocks);
|
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 { "" };
|
if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { " function or" } else { "" };
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => {
|
UnsafetyViolationKind::General => {
|
||||||
// once
|
// once
|
||||||
struct_span_err!(
|
struct_span_err!(
|
||||||
tcx.sess,
|
tcx.sess,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user