diff options
| author | Matthew Jasper <mjjasper1@gmail.com> | 2024-02-27 11:57:52 +0000 |
|---|---|---|
| committer | Matthew Jasper <mjjasper1@gmail.com> | 2024-04-03 08:50:12 +0000 |
| commit | a277c901d95c5fcbb3dbd6608731eebb9e1a01ce (patch) | |
| tree | 6537e75531ca8f2bb59e7cb6ae3903a6225be89f /compiler | |
| parent | 76cf07d5df52c07c3cd4cfeea1ab32b1cfba71bf (diff) | |
| download | rust-a277c901d95c5fcbb3dbd6608731eebb9e1a01ce.tar.gz rust-a277c901d95c5fcbb3dbd6608731eebb9e1a01ce.zip | |
Remove MIR unsafe check
This also remove safety information from MIR.
Diffstat (limited to 'compiler')
20 files changed, 28 insertions, 1050 deletions
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index d763a12f816..1f92cc4d763 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -748,9 +748,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { sess.time("MIR_effect_checking", || { for def_id in tcx.hir().body_owners() { - if !tcx.sess.opts.unstable_opts.thir_unsafeck { - rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id); - } tcx.ensure().has_ffi_unwind_calls(def_id); // If we need to codegen, ensure that we emit all errors from diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 3b78e6a43ab..b9025917d13 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -840,7 +840,6 @@ fn test_unstable_options_tracking_hash() { tracked!(stack_protector, StackProtector::All); tracked!(teach, true); tracked!(thinlto, Some(true)); - tracked!(thir_unsafeck, false); tracked!(tiny_const_eval_limit, true); tracked!(tls_model, Some(TlsModel::GeneralDynamic)); tracked!(translate_remapped_path_to_local_path, false); diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index c90427256b8..bd11b3eb04c 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -35,7 +35,6 @@ macro_rules! arena_types { )>, [] crate_for_resolver: rustc_data_structures::steal::Steal<(rustc_ast::Crate, rustc_ast::AttrVec)>, [] resolutions: rustc_middle::ty::ResolverGlobalCtxt, - [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult, [decode] code_region: rustc_middle::mir::coverage::CodeRegion, [] const_allocs: rustc_middle::mir::interpret::Allocation, [] region_scope_tree: rustc_middle::middle::region::ScopeTree, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index e5a650c5ac4..b87e9ee60be 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -845,17 +845,6 @@ impl<'tcx> Body<'tcx> { } } -#[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)] -pub enum Safety { - Safe, - /// Unsafe because of compiler-generated unsafe code, like `await` desugaring - BuiltinUnsafe, - /// Unsafe because of an unsafe fn - FnUnsafe, - /// Unsafe because of an `unsafe` block - ExplicitUnsafe(hir::HirId), -} - impl<'tcx> Index<BasicBlock> for Body<'tcx> { type Output = BasicBlockData<'tcx>; @@ -1611,8 +1600,6 @@ pub struct SourceScopeData<'tcx> { pub struct SourceScopeLocalData { /// An `HirId` with lint levels equivalent to this scope's lint levels. pub lint_root: hir::HirId, - /// The unsafe block that contains this node. - pub safety: Safety, } /// A collection of projections into user types. @@ -1888,7 +1875,7 @@ mod size_asserts { // tidy-alphabetical-start static_assert_size!(BasicBlockData<'_>, 144); static_assert_size!(LocalDecl<'_>, 40); - static_assert_size!(SourceScopeData<'_>, 72); + static_assert_size!(SourceScopeData<'_>, 64); static_assert_size!(Statement<'_>, 32); static_assert_size!(StatementKind<'_>, 16); static_assert_size!(Terminator<'_>, 112); diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 731e050ca9b..d286c208083 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -3,9 +3,7 @@ use crate::mir; use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt}; use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::unord::UnordSet; use rustc_errors::ErrorGuaranteed; -use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::BitMatrix; use rustc_index::{Idx, IndexVec}; @@ -18,67 +16,6 @@ use std::fmt::{self, Debug}; use super::{ConstValue, SourceInfo}; -#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] -pub enum UnsafetyViolationKind { - /// Unsafe operation outside `unsafe`. - General, - /// Unsafe operation in an `unsafe fn` but outside an `unsafe` block. - /// Has to be handled as a lint for backwards compatibility. - UnsafeFn, -} - -#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] -pub enum UnsafetyViolationDetails { - CallToUnsafeFunction, - UseOfInlineAssembly, - InitializingTypeWith, - CastOfPointerToInt, - UseOfMutableStatic, - UseOfExternStatic, - DerefOfRawPointer, - AccessToUnionField, - MutationOfLayoutConstrainedField, - BorrowOfLayoutConstrainedField, - CallToFunctionWith { - /// Target features enabled in callee's `#[target_feature]` but missing in - /// caller's `#[target_feature]`. - missing: Vec<Symbol>, - /// Target features in `missing` that are enabled at compile time - /// (e.g., with `-C target-feature`). - build_enabled: Vec<Symbol>, - }, -} - -#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] -pub struct UnsafetyViolation { - pub source_info: SourceInfo, - pub lint_root: hir::HirId, - pub kind: UnsafetyViolationKind, - pub details: UnsafetyViolationDetails, -} - -#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] -pub enum UnusedUnsafe { - /// `unsafe` block contains no unsafe operations - /// > ``unnecessary `unsafe` block`` - Unused, - /// `unsafe` block nested under another (used) `unsafe` block - /// > ``… because it's nested under this `unsafe` block`` - InUnsafeBlock(hir::HirId), -} - -#[derive(TyEncodable, TyDecodable, HashStable, Debug)] -pub struct UnsafetyCheckResult { - /// Violations that are propagated *upwards* from this function. - pub violations: Vec<UnsafetyViolation>, - - /// Used `unsafe` blocks in this function. This is used for the "unused_unsafe" lint. - pub used_unsafe_blocks: UnordSet<hir::HirId>, - - /// This is `Some` iff the item is not a closure. - pub unused_unsafes: Option<Vec<(hir::HirId, UnusedUnsafe)>>, -} - rustc_index::newtype_index! { #[derive(HashStable)] #[encodable] diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 5e4454db3e2..62a60a650ec 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -877,12 +877,6 @@ rustc_queries! { desc { |tcx| "collecting all inherent impls for `{:?}`", key } } - /// The result of unsafety-checking this `LocalDefId` with the old checker. - query mir_unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult { - desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) } - cache_on_disk_if { true } - } - /// Unsafety-check this `LocalDefId`. query check_unsafety(key: LocalDefId) { desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) } diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index ddbc0bffaed..e7a1679b151 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -458,7 +458,6 @@ impl_decodable_via_ref! { &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, &'tcx traits::ImplSource<'tcx, ()>, &'tcx mir::Body<'tcx>, - &'tcx mir::UnsafetyCheckResult, &'tcx mir::BorrowCheckResult<'tcx>, &'tcx mir::coverage::CodeRegion, &'tcx ty::List<ty::BoundVariableKind>, diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index 6200f4bda6b..00e99f330f7 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -13,31 +13,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ast_block: BlockId, source_info: SourceInfo, ) -> BlockAnd<()> { - let Block { region_scope, span, ref stmts, expr, targeted_by_break, safety_mode } = + let Block { region_scope, span, ref stmts, expr, targeted_by_break, safety_mode: _ } = self.thir[ast_block]; self.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| { if targeted_by_break { this.in_breakable_scope(None, destination, span, |this| { - Some(this.ast_block_stmts( - destination, - block, - span, - stmts, - expr, - safety_mode, - region_scope, - )) + Some(this.ast_block_stmts(destination, block, span, stmts, expr, region_scope)) }) } else { - this.ast_block_stmts( - destination, - block, - span, - stmts, - expr, - safety_mode, - region_scope, - ) + this.ast_block_stmts(destination, block, span, stmts, expr, region_scope) } }) } @@ -49,7 +33,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span: Span, stmts: &[StmtId], expr: Option<ExprId>, - safety_mode: BlockSafety, region_scope: Scope, ) -> BlockAnd<()> { let this = self; @@ -72,13 +55,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // First we build all the statements in the block. let mut let_scope_stack = Vec::with_capacity(8); let outer_source_scope = this.source_scope; - let outer_in_scope_unsafe = this.in_scope_unsafe; // This scope information is kept for breaking out of the parent remainder scope in case // one let-else pattern matching fails. // By doing so, we can be sure that even temporaries that receive extended lifetime // assignments are dropped, too. let mut last_remainder_scope = region_scope; - this.update_source_scope_for_safety_mode(span, safety_mode); let source_info = this.source_info(span); for stmt in stmts { @@ -202,7 +183,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let_scope_stack.push(remainder_scope); let visibility_scope = - Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None)); + Some(this.new_source_scope(remainder_span, LintLevel::Inherited)); let initializer_span = this.thir[*initializer].span; let scope = (*init_scope, source_info); @@ -271,7 +252,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let remainder_span = remainder_scope.span(this.tcx, this.region_scope_tree); let visibility_scope = - Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None)); + Some(this.new_source_scope(remainder_span, LintLevel::Inherited)); // Evaluate the initializer, if present. if let Some(init) = *initializer { @@ -364,22 +345,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } // Restore the original source scope. this.source_scope = outer_source_scope; - this.in_scope_unsafe = outer_in_scope_unsafe; block.unit() } - - /// If we are entering an unsafe block, create a new source scope - fn update_source_scope_for_safety_mode(&mut self, span: Span, safety_mode: BlockSafety) { - debug!("update_source_scope_for({:?}, {:?})", span, safety_mode); - let new_unsafety = match safety_mode { - BlockSafety::Safe => return, - BlockSafety::BuiltinUnsafe => Safety::BuiltinUnsafe, - BlockSafety::ExplicitUnsafe(hir_id) => { - self.in_scope_unsafe = Safety::ExplicitUnsafe(hir_id); - Safety::ExplicitUnsafe(hir_id) - } - }; - - self.source_scope = self.new_source_scope(span, LintLevel::Inherited, Some(new_unsafety)); - } } diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs index 0475bb8908b..30877e38318 100644 --- a/compiler/rustc_mir_build/src/build/custom/mod.rs +++ b/compiler/rustc_mir_build/src/build/custom/mod.rs @@ -72,10 +72,7 @@ pub(super) fn build_custom_mir<'tcx>( parent_scope: None, inlined: None, inlined_parent_scope: None, - local_data: ClearCrossCrate::Set(SourceScopeLocalData { - lint_root: hir_id, - safety: Safety::Safe, - }), + local_data: ClearCrossCrate::Set(SourceScopeLocalData { lint_root: hir_id }), }); body.injection_phase = Some(parse_attribute(attr)); diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index c77f4a06d05..00600f354ca 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -118,19 +118,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::Box { value } => { let value_ty = this.thir[value].ty; let tcx = this.tcx; - - // `exchange_malloc` is unsafe but box is safe, so need a new scope. - let synth_scope = this.new_source_scope( - expr_span, - LintLevel::Inherited, - Some(Safety::BuiltinUnsafe), - ); - let synth_info = SourceInfo { span: expr_span, scope: synth_scope }; + let source_info = this.source_info(expr_span); let size = this.temp(tcx.types.usize, expr_span); this.cfg.push_assign( block, - synth_info, + source_info, size, Rvalue::NullaryOp(NullOp::SizeOf, value_ty), ); @@ -138,7 +131,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let align = this.temp(tcx.types.usize, expr_span); this.cfg.push_assign( block, - synth_info, + source_info, align, Rvalue::NullaryOp(NullOp::AlignOf, value_ty), ); @@ -154,7 +147,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let success = this.cfg.start_new_block(); this.cfg.terminate( block, - synth_info, + source_info, TerminatorKind::Call { func: exchange_malloc, args: vec![ diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index b4eeeccc127..c8360b6a5fd 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -69,7 +69,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // FIXME: Does this need extra logic to handle let-chains? let source_info = if this.is_let(cond) { let variable_scope = - this.new_source_scope(then_span, LintLevel::Inherited, None); + this.new_source_scope(then_span, LintLevel::Inherited); this.source_scope = variable_scope; SourceInfo { span: then_span, scope: variable_scope } } else { diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index a6b513ce7d0..1ea671a4f79 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -732,7 +732,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut |this, name, mode, var, span, ty, user_ty| { if visibility_scope.is_none() { visibility_scope = - Some(this.new_source_scope(scope_span, LintLevel::Inherited, None)); + Some(this.new_source_scope(scope_span, LintLevel::Inherited)); } let source_info = SourceInfo { span, scope: this.source_scope }; let visibility_scope = visibility_scope.unwrap(); diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 274edf358e0..6972bc00e0b 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -66,17 +66,10 @@ pub(crate) fn mir_build<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx // maybe move the check to a MIR pass? tcx.ensure().check_liveness(def); - if tcx.sess.opts.unstable_opts.thir_unsafeck { - // Don't steal here if THIR unsafeck is being used. Instead - // steal in unsafeck. This is so that pattern inline constants - // can be evaluated as part of building the THIR of the parent - // function without a cycle. - build_mir(&thir.borrow()) - } else { - // We ran all queries that depended on THIR at the beginning - // of `mir_build`, so now we can steal it - build_mir(&thir.steal()) - } + // Don't steal here, instead steal in unsafeck. This is so that + // pattern inline constants can be evaluated as part of building the + // THIR of the parent function without a cycle. + build_mir(&thir.borrow()) } }; @@ -190,9 +183,6 @@ struct Builder<'a, 'tcx> { /// `{ STMTS; EXPR1 } + EXPR2`. block_context: BlockContext, - /// The current unsafe block in scope - in_scope_unsafe: Safety, - /// The vector of all scopes that we have created thus far; /// we track this for debuginfo later. source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>, @@ -470,11 +460,6 @@ fn construct_fn<'tcx>( .output .span(); - let safety = match fn_sig.unsafety { - hir::Unsafety::Normal => Safety::Safe, - hir::Unsafety::Unsafe => Safety::FnUnsafe, - }; - let mut abi = fn_sig.abi; if let DefKind::Closure = tcx.def_kind(fn_def) { // HACK(eddyb) Avoid having RustCall on closures, @@ -520,7 +505,6 @@ fn construct_fn<'tcx>( fn_id, span_with_body, arguments.len(), - safety, return_ty, return_ty_span, coroutine, @@ -590,18 +574,8 @@ fn construct_const<'a, 'tcx>( }; let infcx = tcx.infer_ctxt().build(); - let mut builder = Builder::new( - thir, - infcx, - def, - hir_id, - span, - 0, - Safety::Safe, - const_ty, - const_ty_span, - None, - ); + let mut builder = + Builder::new(thir, infcx, def, hir_id, span, 0, const_ty, const_ty_span, None); let mut block = START_BLOCK; unpack!(block = builder.expr_into_dest(Place::return_place(), block, expr)); @@ -723,10 +697,7 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - parent_scope: None, inlined: None, inlined_parent_scope: None, - local_data: ClearCrossCrate::Set(SourceScopeLocalData { - lint_root: hir_id, - safety: Safety::Safe, - }), + local_data: ClearCrossCrate::Set(SourceScopeLocalData { lint_root: hir_id }), }); cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable); @@ -753,7 +724,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { hir_id: hir::HirId, span: Span, arg_count: usize, - safety: Safety, return_ty: Ty<'tcx>, return_span: Span, coroutine: Option<Box<CoroutineInfo<'tcx>>>, @@ -795,7 +765,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { guard_context: vec![], fixed_temps: Default::default(), fixed_temps_scope: None, - in_scope_unsafe: safety, local_decls: IndexVec::from_elem_n(LocalDecl::new(return_ty, return_span), 1), canonical_user_type_annotations: IndexVec::new(), upvars: CaptureMap::new(), @@ -807,10 +776,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; assert_eq!(builder.cfg.start_new_block(), START_BLOCK); - assert_eq!( - builder.new_source_scope(span, lint_level, Some(safety)), - OUTERMOST_SOURCE_SCOPE - ); + assert_eq!(builder.new_source_scope(span, lint_level), OUTERMOST_SOURCE_SCOPE); builder.source_scopes[OUTERMOST_SOURCE_SCOPE].parent_scope = None; builder @@ -1024,7 +990,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .as_ref() .assert_crate_local() .lint_root; - self.maybe_new_source_scope(pattern_span, None, arg_hir_id, parent_id); + self.maybe_new_source_scope(pattern_span, arg_hir_id, parent_id); } fn get_unit_temp(&mut self) -> Place<'tcx> { diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index aef63896dde..9ac8c1b4417 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -578,7 +578,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let LintLevel::Explicit(current_hir_id) = lint_level { let parent_id = self.source_scopes[source_scope].local_data.as_ref().assert_crate_local().lint_root; - self.maybe_new_source_scope(region_scope.1.span, None, current_hir_id, parent_id); + self.maybe_new_source_scope(region_scope.1.span, current_hir_id, parent_id); } self.push_scope(region_scope); let mut block; @@ -767,7 +767,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn maybe_new_source_scope( &mut self, span: Span, - safety: Option<Safety>, current_id: HirId, parent_id: HirId, ) { @@ -797,7 +796,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if current_root != parent_root { let lint_level = LintLevel::Explicit(current_root); - self.source_scope = self.new_source_scope(span, lint_level, safety); + self.source_scope = self.new_source_scope(span, lint_level); } } @@ -846,18 +845,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } /// Creates a new source scope, nested in the current one. - pub(crate) fn new_source_scope( - &mut self, - span: Span, - lint_level: LintLevel, - safety: Option<Safety>, - ) -> SourceScope { + pub(crate) fn new_source_scope(&mut self, span: Span, lint_level: LintLevel) -> SourceScope { let parent = self.source_scope; debug!( - "new_source_scope({:?}, {:?}, {:?}) - parent({:?})={:?}", + "new_source_scope({:?}, {:?}) - parent({:?})={:?}", span, lint_level, - safety, parent, self.source_scopes.get(parent) ); @@ -867,9 +860,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else { self.source_scopes[parent].local_data.as_ref().assert_crate_local().lint_root }, - safety: safety.unwrap_or_else(|| { - self.source_scopes[parent].local_data.as_ref().assert_crate_local().safety - }), }; self.source_scopes.push(SourceScopeData { span, diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 07dc332b791..8aa9a75d96a 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -909,11 +909,6 @@ impl UnsafeOpKind { } pub fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { - // THIR unsafeck can be disabled with `-Z thir-unsafeck=off` - if !tcx.sess.opts.unstable_opts.thir_unsafeck { - return; - } - // Closures and inline consts are handled by their owner, if it has a body // Also, don't safety check custom MIR if tcx.is_typeck_child(def.to_def_id()) || tcx.has_attr(def, sym::custom_mir) { diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index b8dbdf18db3..f9b79d72b05 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -1,6 +1,4 @@ mir_transform_arithmetic_overflow = this arithmetic operation will overflow -mir_transform_call_to_unsafe_label = call to unsafe function -mir_transform_call_to_unsafe_note = consult the function's documentation for information on how to avoid undefined behavior mir_transform_const_defined_here = `const` item defined here mir_transform_const_modify = attempting to modify a `const` item @@ -11,10 +9,6 @@ mir_transform_const_mut_borrow = taking a mutable reference to a `const` item .note2 = the mutable reference will refer to this temporary, not the original `const` item .note3 = mutable reference created due to call to this method -mir_transform_const_ptr2int_label = cast of pointer to int -mir_transform_const_ptr2int_note = casting pointers to integers in constants -mir_transform_deref_ptr_label = dereference of raw pointer -mir_transform_deref_ptr_note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior mir_transform_ffi_unwind_call = call to {$foreign -> [true] foreign function *[false] function pointer @@ -23,56 +17,13 @@ mir_transform_ffi_unwind_call = call to {$foreign -> mir_transform_fn_item_ref = taking a reference to a function item does not give a function pointer .suggestion = cast `{$ident}` to obtain a function pointer -mir_transform_initializing_valid_range_label = initializing type with `rustc_layout_scalar_valid_range` attr -mir_transform_initializing_valid_range_note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspend point, but should not be .label = the value is held across this suspend point .note = {$reason} .help = consider using a block (`{"{ ... }"}`) to shrink the value's scope, ending before the suspend point - -mir_transform_mutation_layout_constrained_borrow_label = borrow of layout constrained field with interior mutability -mir_transform_mutation_layout_constrained_borrow_note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values -mir_transform_mutation_layout_constrained_label = mutation of layout constrained field -mir_transform_mutation_layout_constrained_note = mutating layout constrained fields cannot statically be checked for valid values mir_transform_operation_will_panic = this operation will panic at runtime -mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in_unsafe_fn_allowed -> - [true] function or block - *[false] block - } - .not_inherited = items do not inherit unsafety from separate enclosing items - -mir_transform_target_feature_call_help = in order for the call to be safe, the context requires the following additional target {$missing_target_features_count -> - [1] feature - *[count] features - }: {$missing_target_features} - -mir_transform_target_feature_call_label = call to function with `#[target_feature]` -mir_transform_target_feature_call_note = the {$build_target_features} target {$build_target_features_count -> - [1] feature - *[count] features - } being enabled in the build configuration does not remove the requirement to list {$build_target_features_count -> - [1] it - *[count] them - } in `#[target_feature]` - mir_transform_unaligned_packed_ref = reference to packed field is unaligned .note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses .note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) .help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) - -mir_transform_union_access_label = access to union field -mir_transform_union_access_note = the field may not be properly initialized: using uninitialized data will cause undefined behavior -mir_transform_unsafe_op_in_unsafe_fn = {$details} is unsafe and requires unsafe block (error E0133) - .suggestion = consider wrapping the function body in an unsafe block - .note = an unsafe function restricts its caller, but its body is safe by default - -mir_transform_unused_unsafe = unnecessary `unsafe` block - .label = because it's nested under this `unsafe` block - -mir_transform_use_of_asm_label = use of inline assembly -mir_transform_use_of_asm_note = inline assembly is entirely unchecked and can cause undefined behavior -mir_transform_use_of_extern_static_label = use of extern static -mir_transform_use_of_extern_static_note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior -mir_transform_use_of_static_mut_label = use of mutable static -mir_transform_use_of_static_mut_note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs deleted file mode 100644 index a0c3de3af58..00000000000 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ /dev/null @@ -1,615 +0,0 @@ -use rustc_data_structures::unord::{ExtendUnord, UnordItems, UnordSet}; -use rustc_hir as hir; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::hir_id::HirId; -use rustc_hir::intravisit; -use rustc_hir::{BlockCheckMode, ExprKind, Node}; -use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::*; -use rustc_middle::query::Providers; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; -use rustc_session::lint::Level; - -use std::ops::Bound; - -use crate::errors; - -pub struct UnsafetyChecker<'a, 'tcx> { - body: &'a Body<'tcx>, - body_did: LocalDefId, - violations: Vec<UnsafetyViolation>, - source_info: SourceInfo, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - - /// Used `unsafe` blocks in this function. This is used for the "unused_unsafe" lint. - used_unsafe_blocks: UnordSet<HirId>, -} - -impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { - fn new( - body: &'a Body<'tcx>, - body_did: LocalDefId, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Self { - Self { - body, - body_did, - violations: vec![], - source_info: SourceInfo::outermost(body.span), - tcx, - param_env, - used_unsafe_blocks: Default::default(), - } - } -} - -impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - self.source_info = terminator.source_info; - match terminator.kind { - TerminatorKind::Goto { .. } - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Drop { .. } - | TerminatorKind::Yield { .. } - | TerminatorKind::Assert { .. } - | TerminatorKind::CoroutineDrop - | TerminatorKind::UnwindResume - | TerminatorKind::UnwindTerminate(_) - | TerminatorKind::Return - | TerminatorKind::Unreachable - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } => { - // safe (at least as emitted during MIR construction) - } - - TerminatorKind::Call { ref func, .. } => { - let func_ty = func.ty(self.body, self.tcx); - let func_id = - if let ty::FnDef(func_id, _) = func_ty.kind() { Some(func_id) } else { None }; - let sig = func_ty.fn_sig(self.tcx); - if let hir::Unsafety::Unsafe = sig.unsafety() { - self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::CallToUnsafeFunction, - ) - } - - if let Some(func_id) = func_id { - self.check_target_features(*func_id); - } - } - - TerminatorKind::InlineAsm { .. } => self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::UseOfInlineAssembly, - ), - } - self.super_terminator(terminator, location); - } - - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - self.source_info = statement.source_info; - match statement.kind { - StatementKind::Assign(..) - | StatementKind::FakeRead(..) - | StatementKind::SetDiscriminant { .. } - | StatementKind::Deinit(..) - | StatementKind::StorageLive(..) - | StatementKind::StorageDead(..) - | StatementKind::Retag { .. } - | StatementKind::PlaceMention(..) - | StatementKind::Coverage(..) - | StatementKind::Intrinsic(..) - | StatementKind::ConstEvalCounter - | StatementKind::Nop => { - // safe (at least as emitted during MIR construction) - } - // `AscribeUserType` just exists to help MIR borrowck. - // It has no semantics, and everything is already reported by `PlaceMention`. - StatementKind::AscribeUserType(..) => return, - } - self.super_statement(statement, location); - } - - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - match rvalue { - Rvalue::Aggregate(box ref aggregate, _) => match aggregate { - &AggregateKind::Array(..) | &AggregateKind::Tuple => {} - &AggregateKind::Adt(adt_did, ..) => { - match self.tcx.layout_scalar_valid_range(adt_did) { - (Bound::Unbounded, Bound::Unbounded) => {} - _ => self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::InitializingTypeWith, - ), - } - } - &AggregateKind::Closure(def_id, _) - | &AggregateKind::CoroutineClosure(def_id, _) - | &AggregateKind::Coroutine(def_id, _) => { - let def_id = def_id.expect_local(); - let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } = - self.tcx.mir_unsafety_check_result(def_id); - self.register_violations(violations, used_unsafe_blocks.items().copied()); - } - }, - _ => {} - } - self.super_rvalue(rvalue, location); - } - - fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) { - if let Operand::Constant(constant) = op { - let maybe_uneval = match constant.const_ { - Const::Val(..) | Const::Ty(_) => None, - Const::Unevaluated(uv, _) => Some(uv), - }; - - if let Some(uv) = maybe_uneval { - if uv.promoted.is_none() { - let def_id = uv.def; - if self.tcx.def_kind(def_id) == DefKind::InlineConst { - let local_def_id = def_id.expect_local(); - let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } = - self.tcx.mir_unsafety_check_result(local_def_id); - self.register_violations(violations, used_unsafe_blocks.items().copied()); - } - } - } - } - self.super_operand(op, location); - } - - fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { - // On types with `scalar_valid_range`, prevent - // * `&mut x.field` - // * `x.field = y;` - // * `&x.field` if `field`'s type has interior mutability - // because either of these would allow modifying the layout constrained field and - // insert values that violate the layout constraints. - if context.is_mutating_use() || context.is_borrow() { - self.check_mut_borrowing_layout_constrained_field(*place, context.is_mutating_use()); - } - - // Some checks below need the extra meta info of the local declaration. - let decl = &self.body.local_decls[place.local]; - - // Check the base local: it might be an unsafe-to-access static. We only check derefs of the - // temporary holding the static pointer to avoid duplicate errors - // <https://github.com/rust-lang/rust/pull/78068#issuecomment-731753506>. - if place.projection.first() == Some(&ProjectionElem::Deref) { - // If the projection root is an artificial local that we introduced when - // desugaring `static`, give a more specific error message - // (avoid the general "raw pointer" clause below, that would only be confusing). - if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() { - if self.tcx.is_mutable_static(def_id) { - self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::UseOfMutableStatic, - ); - return; - } else if self.tcx.is_foreign_item(def_id) { - self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::UseOfExternStatic, - ); - return; - } - } - } - - // Check for raw pointer `Deref`. - for (base, proj) in place.iter_projections() { - if proj == ProjectionElem::Deref { - let base_ty = base.ty(self.body, self.tcx).ty; - if base_ty.is_unsafe_ptr() { - self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::DerefOfRawPointer, - ) - } - } - } - - // Check for union fields. For this we traverse right-to-left, as the last `Deref` changes - // whether we *read* the union field or potentially *write* to it (if this place is being assigned to). - let mut saw_deref = false; - for (base, proj) in place.iter_projections().rev() { - if proj == ProjectionElem::Deref { - saw_deref = true; - continue; - } - - let base_ty = base.ty(self.body, self.tcx).ty; - if base_ty.is_union() { - // If we did not hit a `Deref` yet and the overall place use is an assignment, the - // rules are different. - let assign_to_field = !saw_deref - && matches!( - context, - PlaceContext::MutatingUse( - MutatingUseContext::Store - | MutatingUseContext::Drop - | MutatingUseContext::AsmOutput - ) - ); - // If this is just an assignment, determine if the assigned type needs dropping. - if assign_to_field { - // We have to check the actual type of the assignment, as that determines if the - // old value is being dropped. - let assigned_ty = place.ty(&self.body.local_decls, self.tcx).ty; - if assigned_ty.needs_drop(self.tcx, self.param_env) { - // This would be unsafe, but should be outright impossible since we reject - // such unions. - assert!( - self.tcx.dcx().has_errors().is_some(), - "union fields that need dropping should be impossible: {assigned_ty}" - ); - } - } else { - self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::AccessToUnionField, - ) - } - } - } - } -} - -impl<'tcx> UnsafetyChecker<'_, '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 - .as_ref() - .assert_crate_local() - .lint_root; - self.register_violations( - [&UnsafetyViolation { source_info, lint_root, kind, details }], - UnordItems::empty(), - ); - } - - fn register_violations<'a>( - &mut self, - violations: impl IntoIterator<Item = &'a UnsafetyViolation>, - new_used_unsafe_blocks: UnordItems<HirId, impl Iterator<Item = HirId>>, - ) { - let safety = self.body.source_scopes[self.source_info.scope] - .local_data - .as_ref() - .assert_crate_local() - .safety; - match safety { - // `unsafe` blocks are required in safe code - Safety::Safe => violations.into_iter().for_each(|violation| { - match violation.kind { - UnsafetyViolationKind::General => {} - UnsafetyViolationKind::UnsafeFn => { - bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context") - } - } - if !self.violations.contains(violation) { - self.violations.push(violation.clone()) - } - }), - // With the RFC 2585, no longer allow `unsafe` operations in `unsafe fn`s - Safety::FnUnsafe => violations.into_iter().for_each(|violation| { - let mut violation = violation.clone(); - violation.kind = UnsafetyViolationKind::UnsafeFn; - if !self.violations.contains(&violation) { - self.violations.push(violation) - } - }), - Safety::BuiltinUnsafe => {} - Safety::ExplicitUnsafe(hir_id) => violations.into_iter().for_each(|_violation| { - self.used_unsafe_blocks.insert(hir_id); - }), - }; - - self.used_unsafe_blocks.extend_unord(new_used_unsafe_blocks); - } - fn check_mut_borrowing_layout_constrained_field( - &mut self, - place: Place<'tcx>, - is_mut_use: bool, - ) { - for (place_base, elem) in place.iter_projections().rev() { - match elem { - // Modifications behind a dereference don't affect the value of - // the pointer. - ProjectionElem::Deref => return, - ProjectionElem::Field(..) => { - let ty = place_base.ty(&self.body.local_decls, self.tcx).ty; - if let ty::Adt(def, _) = ty.kind() { - if self.tcx.layout_scalar_valid_range(def.did()) - != (Bound::Unbounded, Bound::Unbounded) - { - let details = if is_mut_use { - UnsafetyViolationDetails::MutationOfLayoutConstrainedField - - // Check `is_freeze` as late as possible to avoid cycle errors - // with opaque types. - } else if !place - .ty(self.body, self.tcx) - .ty - .is_freeze(self.tcx, self.param_env) - { - UnsafetyViolationDetails::BorrowOfLayoutConstrainedField - } else { - continue; - }; - self.require_unsafe(UnsafetyViolationKind::General, details); - } - } - } - _ => {} - } - } - } - - /// Checks whether calling `func_did` needs an `unsafe` context or not, i.e. whether - /// the called function has target features the calling function hasn't. - fn check_target_features(&mut self, func_did: DefId) { - // Unsafety isn't required on wasm targets. For more information see - // the corresponding check in typeck/src/collect.rs - if self.tcx.sess.target.options.is_like_wasm { - return; - } - - let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features; - // The body might be a constant, so it doesn't have codegen attributes. - let self_features = &self.tcx.body_codegen_attrs(self.body_did.to_def_id()).target_features; - - // Is `callee_features` a subset of `calling_features`? - if !callee_features.iter().all(|feature| self_features.contains(feature)) { - let missing: Vec<_> = callee_features - .iter() - .copied() - .filter(|feature| !self_features.contains(feature)) - .collect(); - let build_enabled = self - .tcx - .sess - .target_features - .iter() - .copied() - .filter(|feature| missing.contains(feature)) - .collect(); - self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::CallToFunctionWith { missing, build_enabled }, - ) - } - } -} - -pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { mir_unsafety_check_result, ..*providers }; -} - -/// Context information for [`UnusedUnsafeVisitor`] traversal, -/// saves (innermost) relevant context -#[derive(Copy, Clone, Debug)] -enum Context { - Safe, - /// in an `unsafe fn` - UnsafeFn, - /// in a *used* `unsafe` block - /// (i.e. a block without unused-unsafe warning) - UnsafeBlock(HirId), -} - -struct UnusedUnsafeVisitor<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - used_unsafe_blocks: &'a UnordSet<HirId>, - context: Context, - unused_unsafes: &'a mut Vec<(HirId, UnusedUnsafe)>, -} - -impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> { - fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) { - if let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = block.rules { - let used = match self.tcx.lint_level_at_node(UNUSED_UNSAFE, block.hir_id) { - (Level::Allow, _) => true, - _ => self.used_unsafe_blocks.contains(&block.hir_id), - }; - let unused_unsafe = match (self.context, used) { - (_, false) => UnusedUnsafe::Unused, - (Context::Safe, true) | (Context::UnsafeFn, true) => { - let previous_context = self.context; - self.context = Context::UnsafeBlock(block.hir_id); - intravisit::walk_block(self, block); - self.context = previous_context; - return; - } - (Context::UnsafeBlock(hir_id), true) => UnusedUnsafe::InUnsafeBlock(hir_id), - }; - self.unused_unsafes.push((block.hir_id, unused_unsafe)); - } - intravisit::walk_block(self, block); - } - - fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) { - self.visit_body(self.tcx.hir().body(c.body)) - } - - fn visit_fn( - &mut self, - fk: intravisit::FnKind<'tcx>, - _fd: &'tcx hir::FnDecl<'tcx>, - b: hir::BodyId, - _s: rustc_span::Span, - _id: LocalDefId, - ) { - if matches!(fk, intravisit::FnKind::Closure) { - self.visit_body(self.tcx.hir().body(b)) - } - } -} - -fn check_unused_unsafe( - tcx: TyCtxt<'_>, - def_id: LocalDefId, - used_unsafe_blocks: &UnordSet<HirId>, -) -> Vec<(HirId, UnusedUnsafe)> { - let body_id = tcx.hir().maybe_body_owned_by(def_id); - - let Some(body_id) = body_id else { - debug!("check_unused_unsafe({:?}) - no body found", def_id); - return vec![]; - }; - - let body = tcx.hir().body(body_id); - let hir_id = tcx.local_def_id_to_hir_id(def_id); - let context = match tcx.hir().fn_sig_by_hir_id(hir_id) { - Some(sig) if sig.header.unsafety == hir::Unsafety::Unsafe => Context::UnsafeFn, - _ => Context::Safe, - }; - - debug!( - "check_unused_unsafe({:?}, context={:?}, body={:?}, used_unsafe_blocks={:?})", - def_id, body, context, used_unsafe_blocks - ); - - let mut unused_unsafes = vec![]; - - let mut visitor = UnusedUnsafeVisitor { - tcx, - used_unsafe_blocks, - context, - unused_unsafes: &mut unused_unsafes, - }; - intravisit::Visitor::visit_body(&mut visitor, body); - - unused_unsafes -} - -fn mir_unsafety_check_result(tcx: TyCtxt<'_>, def: LocalDefId) -> &UnsafetyCheckResult { - debug!("unsafety_violations({:?})", def); - - // N.B., this borrow is valid because all the consumers of - // `mir_built` force this. - let body = &tcx.mir_built(def).borrow(); - - if body.is_custom_mir() || body.tainted_by_errors.is_some() { - return tcx.arena.alloc(UnsafetyCheckResult { - violations: Vec::new(), - used_unsafe_blocks: Default::default(), - unused_unsafes: Some(Vec::new()), - }); - } - - let param_env = tcx.param_env(def); - - let mut checker = UnsafetyChecker::new(body, def, tcx, param_env); - checker.visit_body(body); - - let unused_unsafes = (!tcx.is_typeck_child(def.to_def_id())) - .then(|| check_unused_unsafe(tcx, def, &checker.used_unsafe_blocks)); - - tcx.arena.alloc(UnsafetyCheckResult { - violations: checker.violations, - used_unsafe_blocks: checker.used_unsafe_blocks, - unused_unsafes, - }) -} - -fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) { - let span = tcx.sess.source_map().guess_head_span(tcx.hir().span(id)); - let nested_parent = if let UnusedUnsafe::InUnsafeBlock(id) = kind { - Some(tcx.sess.source_map().guess_head_span(tcx.hir().span(id))) - } else { - None - }; - tcx.emit_node_span_lint(UNUSED_UNSAFE, id, span, errors::UnusedUnsafe { span, nested_parent }); -} - -pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) { - debug!("check_unsafety({:?})", def_id); - - // closures and inline consts are handled by their parent fn. - if tcx.is_typeck_child(def_id.to_def_id()) { - return; - } - - let UnsafetyCheckResult { violations, unused_unsafes, .. } = - tcx.mir_unsafety_check_result(def_id); - // Only suggest wrapping the entire function body in an unsafe block once - let mut suggest_unsafe_block = true; - - for &UnsafetyViolation { source_info, lint_root, kind, ref details } in violations.iter() { - let details = - errors::RequiresUnsafeDetail { violation: details.clone(), span: source_info.span }; - - match kind { - UnsafetyViolationKind::General => { - let op_in_unsafe_fn_allowed = unsafe_op_in_unsafe_fn_allowed(tcx, lint_root); - let note_non_inherited = tcx.hir().parent_iter(lint_root).find(|(id, node)| { - if let Node::Expr(block) = node - && let ExprKind::Block(block, _) = block.kind - && let BlockCheckMode::UnsafeBlock(_) = block.rules - { - true - } else if let Some(sig) = tcx.hir().fn_sig_by_hir_id(*id) - && sig.header.is_unsafe() - { - true - } else { - false - } - }); - let enclosing = if let Some((id, _)) = note_non_inherited { - Some(tcx.sess.source_map().guess_head_span(tcx.hir().span(id))) - } else { - None - }; - tcx.dcx().emit_err(errors::RequiresUnsafe { - span: source_info.span, - enclosing, - details, - op_in_unsafe_fn_allowed, - }); - } - UnsafetyViolationKind::UnsafeFn => { - tcx.emit_node_span_lint( - UNSAFE_OP_IN_UNSAFE_FN, - lint_root, - source_info.span, - errors::UnsafeOpInUnsafeFn { - details, - suggest_unsafe_block: suggest_unsafe_block.then(|| { - let hir_id = tcx.local_def_id_to_hir_id(def_id); - let fn_sig = tcx - .hir() - .fn_sig_by_hir_id(hir_id) - .expect("this violation only occurs in fn"); - let body = tcx.hir().body_owned_by(def_id); - let body_span = tcx.hir().body(body).value.span; - let start = tcx.sess.source_map().start_point(body_span).shrink_to_hi(); - let end = tcx.sess.source_map().end_point(body_span).shrink_to_lo(); - (start, end, fn_sig.span) - }), - }, - ); - suggest_unsafe_block = false; - } - } - } - - for &(block_id, kind) in unused_unsafes.as_ref().unwrap() { - report_unused_unsafe(tcx, kind, block_id); - } -} - -fn unsafe_op_in_unsafe_fn_allowed(tcx: TyCtxt<'_>, id: HirId) -> bool { - tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, id).0 == Level::Allow -} diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 9297bc51fad..0634e321ea3 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -1,11 +1,6 @@ -use std::borrow::Cow; - -use rustc_errors::{ - codes::*, Applicability, Diag, DiagArgValue, DiagCtxt, DiagMessage, Diagnostic, - EmissionGuarantee, Level, LintDiagnostic, -}; +use rustc_errors::{codes::*, Diag, DiagMessage, LintDiagnostic}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; -use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails}; +use rustc_middle::mir::AssertKind; use rustc_middle::ty::TyCtxt; use rustc_session::lint::{self, Lint}; use rustc_span::def_id::DefId; @@ -42,168 +37,6 @@ pub(crate) struct UnalignedPackedRef { pub span: Span, } -#[derive(LintDiagnostic)] -#[diag(mir_transform_unused_unsafe)] -pub(crate) struct UnusedUnsafe { - #[label(mir_transform_unused_unsafe)] - pub span: Span, - #[label] - pub nested_parent: Option<Span>, -} - -pub(crate) struct RequiresUnsafe { - pub span: Span, - pub details: RequiresUnsafeDetail, - pub enclosing: Option<Span>, - pub op_in_unsafe_fn_allowed: bool, -} - -// The primary message for this diagnostic should be '{$label} is unsafe and...', -// so we need to eagerly translate the label here, which isn't supported by the derive API -// We could also exhaustively list out the primary messages for all unsafe violations, -// but this would result in a lot of duplication. -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for RequiresUnsafe { - #[track_caller] - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { - let mut diag = Diag::new(dcx, level, fluent::mir_transform_requires_unsafe); - diag.code(E0133); - diag.span(self.span); - diag.span_label(self.span, self.details.label()); - let desc = dcx.eagerly_translate_to_string(self.details.label(), [].into_iter()); - diag.arg("details", desc); - diag.arg("op_in_unsafe_fn_allowed", self.op_in_unsafe_fn_allowed); - self.details.add_subdiagnostics(&mut diag); - if let Some(sp) = self.enclosing { - diag.span_label(sp, fluent::mir_transform_not_inherited); - } - diag - } -} - -#[derive(Clone)] -pub(crate) struct RequiresUnsafeDetail { - pub span: Span, - pub violation: UnsafetyViolationDetails, -} - -impl RequiresUnsafeDetail { - // FIXME: make this translatable - #[allow(rustc::diagnostic_outside_of_impl)] - #[allow(rustc::untranslatable_diagnostic)] - fn add_subdiagnostics<G: EmissionGuarantee>(&self, diag: &mut Diag<'_, G>) { - use UnsafetyViolationDetails::*; - match self.violation { - CallToUnsafeFunction => { - diag.note(fluent::mir_transform_call_to_unsafe_note); - } - UseOfInlineAssembly => { - diag.note(fluent::mir_transform_use_of_asm_note); - } - InitializingTypeWith => { - diag.note(fluent::mir_transform_initializing_valid_range_note); - } - CastOfPointerToInt => { - diag.note(fluent::mir_transform_const_ptr2int_note); - } - UseOfMutableStatic => { - diag.note(fluent::mir_transform_use_of_static_mut_note); - } - UseOfExternStatic => { - diag.note(fluent::mir_transform_use_of_extern_static_note); - } - DerefOfRawPointer => { - diag.note(fluent::mir_transform_deref_ptr_note); - } - AccessToUnionField => { - diag.note(fluent::mir_transform_union_access_note); - } - MutationOfLayoutConstrainedField => { - diag.note(fluent::mir_transform_mutation_layout_constrained_note); - } - BorrowOfLayoutConstrainedField => { - diag.note(fluent::mir_transform_mutation_layout_constrained_borrow_note); - } - CallToFunctionWith { ref missing, ref build_enabled } => { - diag.help(fluent::mir_transform_target_feature_call_help); - diag.arg( - "missing_target_features", - DiagArgValue::StrListSepByAnd( - missing.iter().map(|feature| Cow::from(feature.to_string())).collect(), - ), - ); - diag.arg("missing_target_features_count", missing.len()); - if !build_enabled.is_empty() { - diag.note(fluent::mir_transform_target_feature_call_note); - diag.arg( - "build_target_features", - DiagArgValue::StrListSepByAnd( - build_enabled - .iter() - .map(|feature| Cow::from(feature.to_string())) - .collect(), - ), - ); - diag.arg("build_target_features_count", build_enabled.len()); - } - } - } - } - - fn label(&self) -> DiagMessage { - use UnsafetyViolationDetails::*; - match self.violation { - CallToUnsafeFunction => fluent::mir_transform_call_to_unsafe_label, - UseOfInlineAssembly => fluent::mir_transform_use_of_asm_label, - InitializingTypeWith => fluent::mir_transform_initializing_valid_range_label, - CastOfPointerToInt => fluent::mir_transform_const_ptr2int_label, - UseOfMutableStatic => fluent::mir_transform_use_of_static_mut_label, - UseOfExternStatic => fluent::mir_transform_use_of_extern_static_label, - DerefOfRawPointer => fluent::mir_transform_deref_ptr_label, - AccessToUnionField => fluent::mir_transform_union_access_label, - MutationOfLayoutConstrainedField => { - fluent::mir_transform_mutation_layout_constrained_label - } - BorrowOfLayoutConstrainedField => { - fluent::mir_transform_mutation_layout_constrained_borrow_label - } - CallToFunctionWith { .. } => fluent::mir_transform_target_feature_call_label, - } - } -} - -pub(crate) struct UnsafeOpInUnsafeFn { - pub details: RequiresUnsafeDetail, - - /// These spans point to: - /// 1. the start of the function body - /// 2. the end of the function body - /// 3. the function signature - pub suggest_unsafe_block: Option<(Span, Span, Span)>, -} - -impl<'a> LintDiagnostic<'a, ()> for UnsafeOpInUnsafeFn { - #[track_caller] - fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { - let desc = diag.dcx.eagerly_translate_to_string(self.details.label(), [].into_iter()); - diag.arg("details", desc); - diag.span_label(self.details.span, self.details.label()); - self.details.add_subdiagnostics(diag); - - if let Some((start, end, fn_sig)) = self.suggest_unsafe_block { - diag.span_note(fn_sig, fluent::mir_transform_note); - diag.tool_only_multipart_suggestion( - fluent::mir_transform_suggestion, - vec![(start, " unsafe {".into()), (end, "}".into())], - Applicability::MaybeIncorrect, - ); - } - } - - fn msg(&self) -> DiagMessage { - fluent::mir_transform_unsafe_op_in_unsafe_fn - } -} - pub(crate) struct AssertLint<P> { pub span: Span, pub assert_kind: AssertKind<P>, diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index a684f9bdff1..e477c068229 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -53,7 +53,6 @@ mod add_moves_for_packed_drops; mod add_retag; mod check_const_item_mutation; mod check_packed_ref; -pub mod check_unsafety; mod remove_place_mention; // This pass is public to allow external drivers to perform MIR cleanup mod add_subtyping_projections; @@ -120,7 +119,6 @@ use rustc_mir_dataflow::rustc_peek; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub fn provide(providers: &mut Providers) { - check_unsafety::provide(providers); coverage::query::provide(providers); ffi_unwind_calls::provide(providers); shim::provide(providers); @@ -280,11 +278,6 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs { } fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> { - // MIR unsafety check uses the raw mir, so make sure it is run. - if !tcx.sess.opts.unstable_opts.thir_unsafeck { - tcx.ensure_with_value().mir_unsafety_check_result(def); - } - let mut body = tcx.build_mir(def); pass_manager::dump_mir_for_phase_change(tcx, &body); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 6204f868385..a76eb6b06aa 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1950,8 +1950,6 @@ written to standard error output)"), #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")] thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED], "enable ThinLTO when possible"), - thir_unsafeck: bool = (true, parse_bool, [TRACKED], - "use the THIR unsafety checker (default: yes)"), /// We default to 1 here since we want to behave like /// a sequential compiler for now. This'll likely be adjusted /// in the future. Note that -Zthreads=0 is the way to get |
