From f6feccf9413879d52c42a6daa204266c982b9f09 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 30 Oct 2023 22:29:32 -0400 Subject: [PATCH] Move alignment checks to codegen --- compiler/rustc_borrowck/src/invalidation.rs | 3 +- compiler/rustc_borrowck/src/lib.rs | 6 +- compiler/rustc_borrowck/src/type_check/mod.rs | 6 +- compiler/rustc_codegen_cranelift/src/base.rs | 5 + .../rustc_codegen_cranelift/src/constant.rs | 3 +- compiler/rustc_codegen_ssa/src/mir/analyze.rs | 3 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 80 +++++++++- .../src/interpret/terminator.rs | 2 +- .../src/transform/check_consts/check.rs | 3 +- .../check_consts/post_drop_elaboration.rs | 3 +- .../src/transform/validate.rs | 5 +- compiler/rustc_middle/src/mir/pretty.rs | 5 +- compiler/rustc_middle/src/mir/syntax.rs | 23 ++- compiler/rustc_middle/src/mir/terminator.rs | 18 +-- compiler/rustc_middle/src/mir/visit.rs | 6 + compiler/rustc_mir_build/src/build/scope.rs | 3 +- compiler/rustc_mir_build/src/lints.rs | 3 +- .../src/impls/borrowed_locals.rs | 3 +- .../src/impls/storage_liveness.rs | 6 +- .../src/move_paths/builder.rs | 1 + .../rustc_mir_dataflow/src/value_analysis.rs | 3 +- .../src/check_alignment.rs | 141 ++---------------- .../rustc_mir_transform/src/check_unsafety.rs | 3 +- .../src/const_prop_lint.rs | 3 +- compiler/rustc_mir_transform/src/coroutine.rs | 6 +- .../rustc_mir_transform/src/coverage/graph.rs | 3 +- .../src/coverage/spans/from_mir.rs | 3 +- compiler/rustc_mir_transform/src/dest_prop.rs | 8 +- compiler/rustc_mir_transform/src/inline.rs | 3 +- .../rustc_mir_transform/src/jump_threading.rs | 2 +- .../src/remove_noop_landing_pads.rs | 3 +- .../src/separate_const_switch.rs | 7 +- compiler/rustc_monomorphize/src/collector.rs | 3 +- compiler/rustc_smir/src/rustc_smir/mod.rs | 1 + compiler/stable_mir/src/mir/body.rs | 1 + compiler/stable_mir/src/mir/visit.rs | 1 + .../clippy_utils/src/qualify_min_const_fn.rs | 3 +- 37 files changed, 209 insertions(+), 172 deletions(-) diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index 7b5b52e39b121..fc8966e7d4d29 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -205,7 +205,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { | TerminatorKind::UnwindTerminate(_) | TerminatorKind::Unreachable | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ } - | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => { + | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } + | TerminatorKind::UbCheck { .. } => { // no data used, thus irrelevant to borrowck } } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 1a74582389d1e..c59b3bedd570f 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -785,7 +785,8 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro | TerminatorKind::Return | TerminatorKind::CoroutineDrop | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ } - | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => { + | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } + | TerminatorKind::UbCheck { .. } => { // no data used, thus irrelevant to borrowck } } @@ -835,7 +836,8 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro | TerminatorKind::Goto { .. } | TerminatorKind::SwitchInt { .. } | TerminatorKind::Unreachable - | TerminatorKind::InlineAsm { .. } => {} + | TerminatorKind::InlineAsm { .. } + | TerminatorKind::UbCheck { .. } => {} } } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 9f30d9d8ba12b..8c1a4e9d8edab 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1358,7 +1358,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | TerminatorKind::Drop { .. } | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::InlineAsm { .. } => { + | TerminatorKind::InlineAsm { .. } + | TerminatorKind::UbCheck { .. } => { // no checks needed for these } @@ -1690,6 +1691,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup); } + TerminatorKind::UbCheck { target, .. } => { + self.assert_iscleanup(body, block_data, target, is_cleanup) + } } } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 80e7c5bd9edbc..2df7f4e91e966 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -488,6 +488,11 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { let target_block = fx.get_block(*target); fx.bcx.ins().jump(target_block, &[]); } + // FIXME + TerminatorKind::UbCheck { target, .. } => { + let block = fx.get_block(*target); + fx.bcx.ins().jump(block, &[]); + } }; } } diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index b0853d30e03b8..7682e63d2872a 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -508,7 +508,8 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::Drop { .. } - | TerminatorKind::Assert { .. } => {} + | TerminatorKind::Assert { .. } + | TerminatorKind::UbCheck { .. } => {} TerminatorKind::Yield { .. } | TerminatorKind::CoroutineDrop | TerminatorKind::FalseEdge { .. } diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index 53cc063e55a54..5ef7576fead40 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -277,7 +277,8 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec { /* nothing to do */ } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::UbCheck { .. } => { /* nothing to do */ } TerminatorKind::Call { unwind, .. } | TerminatorKind::InlineAsm { unwind, .. } | TerminatorKind::Assert { unwind, .. } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 22afb4063267e..10ad5517882c7 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -12,7 +12,7 @@ use crate::MemFlags; use rustc_ast as ast; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir::lang_items::LangItem; -use rustc_middle::mir::{self, AssertKind, SwitchTargets, UnwindTerminateReason}; +use rustc_middle::mir::{self, AssertKind, SwitchTargets, UbCheckKind, UnwindTerminateReason}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Instance, Ty}; @@ -737,6 +737,79 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } + fn codegen_alignment_check( + &mut self, + helper: &TerminatorCodegenHelper<'tcx>, + bx: &mut Bx, + pointer: &mir::Operand<'tcx>, + source_info: mir::SourceInfo, + target: mir::BasicBlock, + ) -> MergingSucc { + let span = source_info.span; + let pointer = self.codegen_operand(bx, pointer); + let pointee_ty = pointer.layout.ty.builtin_deref(true).unwrap(); + let pointee_layout = bx.layout_of(pointee_ty.ty); + + let mk_usize = |v: u64| { + let layout = bx.layout_of(bx.tcx().types.usize); + let rustc_target::abi::Abi::Scalar(abi) = layout.abi else { unreachable!() }; + let v = rustc_middle::mir::interpret::Scalar::from_target_usize(v, &bx.tcx()); + bx.scalar_to_backend(v, abi, bx.cx().type_isize()) + }; + + let align = pointee_layout.align.abi.bytes(); + let mask = mk_usize(align - 1); + let zero = mk_usize(0); + let required = mk_usize(align); + + let ptr_imm = match pointer.val { + crate::mir::OperandValue::Immediate(imm) => imm, + crate::mir::OperandValue::Pair(ptr, _) => ptr, + _ => { + unreachable!("{pointer:?}"); + } + }; + let int_imm = bx.ptrtoint(ptr_imm, bx.cx().type_isize()); + + let masked = bx.and(int_imm, mask); + + let is_zero = bx.icmp( + crate::base::bin_op_to_icmp_predicate(mir::BinOp::Eq.to_hir_binop(), false), + masked, + zero, + ); + + let lltarget = helper.llbb_with_cleanup(self, target); + let panic_block = bx.append_sibling_block("panic"); + + bx.cond_br(is_zero, lltarget, panic_block); + + bx.switch_to_block(panic_block); + self.set_debug_loc(bx, source_info); + + let location = self.get_caller_location(bx, source_info).immediate(); + + let found = int_imm; + + let (lang_item, args) = + (LangItem::PanicMisalignedPointerDereference, vec![required, found, location]); + + let (fn_abi, llfn) = common::build_langcall(bx, Some(span), lang_item); + let merging_succ = helper.do_call( + self, + bx, + fn_abi, + llfn, + &args, + None, + mir::UnwindAction::Unreachable, + &[], + false, + ); + assert_eq!(merging_succ, MergingSucc::False); + MergingSucc::False + } + fn codegen_call_terminator( &mut self, helper: TerminatorCodegenHelper<'tcx>, @@ -1292,6 +1365,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.instance, mergeable_succ(), ), + + mir::TerminatorKind::UbCheck { + target, + kind: UbCheckKind::PointerAlignment { ref pointer }, + } => self.codegen_alignment_check(&helper, bx, pointer, terminator.source_info, target), } } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index b54c668145638..ceafa503f92b8 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -85,7 +85,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.pop_stack_frame(/* unwinding */ false)? } - Goto { target } => self.go_to_block(target), + Goto { target } | UbCheck { target, .. } => self.go_to_block(target), SwitchInt { ref discr, ref targets } => { let discr = self.read_immediate(&self.eval_operand(discr, None)?)?; diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 135c99fefbc85..f77f4e4309f88 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -1058,7 +1058,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { | TerminatorKind::UnwindResume | TerminatorKind::Return | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Unreachable => {} + | TerminatorKind::Unreachable + | TerminatorKind::UbCheck { .. } => {} } } } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs index aff256b3eadd6..42c1c2bbf55d5 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs @@ -118,7 +118,8 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> { | mir::TerminatorKind::Return | mir::TerminatorKind::SwitchInt { .. } | mir::TerminatorKind::Unreachable - | mir::TerminatorKind::Yield { .. } => {} + | mir::TerminatorKind::Yield { .. } + | mir::TerminatorKind::UbCheck { .. } => {} } } } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index b70a342aa15e6..ca610ed331dc3 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -393,7 +393,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { match &terminator.kind { - TerminatorKind::Goto { target } => { + TerminatorKind::Goto { target } | TerminatorKind::UbCheck { target, .. } => { self.check_edge(location, *target, EdgeKind::Normal); } TerminatorKind::SwitchInt { targets, discr: _ } => { @@ -1299,7 +1299,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { | TerminatorKind::UnwindResume | TerminatorKind::UnwindTerminate(_) | TerminatorKind::Return - | TerminatorKind::Unreachable => {} + | TerminatorKind::Unreachable + | TerminatorKind::UbCheck { .. } => {} } self.super_terminator(terminator, location); diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 5f4ff22bc49ca..f4dabe69dbb82 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -858,6 +858,9 @@ impl<'tcx> TerminatorKind<'tcx> { } write!(fmt, ", options({options:?}))") } + UbCheck { target: _, kind: UbCheckKind::PointerAlignment { pointer } } => { + write!(fmt, "pointer_alignment_check({pointer:?})") + } } } @@ -866,7 +869,7 @@ impl<'tcx> TerminatorKind<'tcx> { use self::TerminatorKind::*; match *self { Return | UnwindResume | UnwindTerminate(_) | Unreachable | CoroutineDrop => vec![], - Goto { .. } => vec!["".into()], + Goto { .. } | UbCheck { .. } => vec!["".into()], SwitchInt { ref targets, .. } => targets .values .iter() diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index b89c7bc512e1e..d04649c3b4f5f 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -588,7 +588,9 @@ impl CallSource { #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)] pub enum TerminatorKind<'tcx> { /// Block has one successor; we continue execution there. - Goto { target: BasicBlock }, + Goto { + target: BasicBlock, + }, /// Switches based on the computed value. /// @@ -655,7 +657,12 @@ pub enum TerminatorKind<'tcx> { /// The `replace` flag indicates whether this terminator was created as part of an assignment. /// This should only be used for diagnostic purposes, and does not have any operational /// meaning. - Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction, replace: bool }, + Drop { + place: Place<'tcx>, + target: BasicBlock, + unwind: UnwindAction, + replace: bool, + }, /// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of /// the referred to function. The operand types must match the argument types of the function. @@ -798,6 +805,17 @@ pub enum TerminatorKind<'tcx> { /// if and only if InlineAsmOptions::MAY_UNWIND is set. unwind: UnwindAction, }, + + UbCheck { + target: BasicBlock, + kind: UbCheckKind<'tcx>, + }, +} + +#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)] +#[derive(Debug)] +pub enum UbCheckKind<'tcx> { + PointerAlignment { pointer: Operand<'tcx> }, } impl TerminatorKind<'_> { @@ -819,6 +837,7 @@ impl TerminatorKind<'_> { TerminatorKind::FalseEdge { .. } => "FalseEdge", TerminatorKind::FalseUnwind { .. } => "FalseUnwind", TerminatorKind::InlineAsm { .. } => "InlineAsm", + TerminatorKind::UbCheck { .. } => "UbCheck", } } } diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 9dfbe1733cc51..aeaf6dfe459c9 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -348,9 +348,8 @@ impl<'tcx> TerminatorKind<'tcx> { | Assert { target: t, unwind: _, .. } | FalseUnwind { real_target: t, unwind: _ } | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. } - | InlineAsm { destination: Some(t), unwind: _, .. } => { - Some(t).into_iter().chain((&[]).into_iter().copied()) - } + | InlineAsm { destination: Some(t), unwind: _, .. } + | UbCheck { target: t, .. } => Some(t).into_iter().chain((&[]).into_iter().copied()), UnwindResume | UnwindTerminate(_) | CoroutineDrop @@ -390,9 +389,8 @@ impl<'tcx> TerminatorKind<'tcx> { | Assert { target: ref mut t, unwind: _, .. } | FalseUnwind { real_target: ref mut t, unwind: _ } | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(ref mut t), .. } - | InlineAsm { destination: Some(ref mut t), unwind: _, .. } => { - Some(t).into_iter().chain(&mut []) - } + | InlineAsm { destination: Some(ref mut t), unwind: _, .. } + | UbCheck { target: ref mut t, .. } => Some(t).into_iter().chain(&mut []), UnwindResume | UnwindTerminate(_) | CoroutineDrop @@ -417,7 +415,8 @@ impl<'tcx> TerminatorKind<'tcx> { | TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } | TerminatorKind::SwitchInt { .. } - | TerminatorKind::FalseEdge { .. } => None, + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::UbCheck { .. } => None, TerminatorKind::Call { ref unwind, .. } | TerminatorKind::Assert { ref unwind, .. } | TerminatorKind::Drop { ref unwind, .. } @@ -436,7 +435,8 @@ impl<'tcx> TerminatorKind<'tcx> { | TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } | TerminatorKind::SwitchInt { .. } - | TerminatorKind::FalseEdge { .. } => None, + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::UbCheck { .. } => None, TerminatorKind::Call { ref mut unwind, .. } | TerminatorKind::Assert { ref mut unwind, .. } | TerminatorKind::Drop { ref mut unwind, .. } @@ -519,7 +519,7 @@ impl<'tcx> TerminatorKind<'tcx> { TerminatorEdges::None } - Goto { target } => TerminatorEdges::Single(target), + Goto { target } | UbCheck { target, .. } => TerminatorEdges::Single(target), Assert { target, unwind, expected: _, msg: _, cond: _ } | Drop { target, unwind, place: _, replace: _ } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 0f0ca3a1420e9..c385bd6761505 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -599,6 +599,12 @@ macro_rules! make_mir_visitor { } } } + TerminatorKind::UbCheck { + kind: UbCheckKind::PointerAlignment { pointer }, + target: _, + } => { + self.visit_operand(pointer, location) + } } } diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index b3d3863b5db77..1f7dadaf4b252 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -1512,7 +1512,8 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind { | TerminatorKind::Unreachable | TerminatorKind::Yield { .. } | TerminatorKind::CoroutineDrop - | TerminatorKind::FalseEdge { .. } => { + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::UbCheck { .. } => { span_bug!(term.source_info.span, "cannot unwind from {:?}", term.kind) } } diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index acf4d6bc2a071..a29a7faa4c030 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -214,7 +214,8 @@ impl<'mir, 'tcx, C: TerminatorClassifier<'tcx>> TriColorVisitor ControlFlow::Continue(()), + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::UbCheck { .. } => ControlFlow::Continue(()), } } diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 1e8e09ac333b1..7065263dd46fb 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -143,7 +143,8 @@ where | TerminatorKind::Return | TerminatorKind::SwitchInt { .. } | TerminatorKind::Unreachable - | TerminatorKind::Yield { .. } => {} + | TerminatorKind::Yield { .. } + | TerminatorKind::UbCheck { .. } => {} } } } diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 5a58e3af8be1a..e6065648ca0d8 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -301,7 +301,8 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { | TerminatorKind::UnwindResume | TerminatorKind::Return | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Unreachable => {} + | TerminatorKind::Unreachable + | TerminatorKind::UbCheck { .. } => {} } } @@ -338,7 +339,8 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { | TerminatorKind::UnwindResume | TerminatorKind::Return | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Unreachable => {} + | TerminatorKind::Unreachable + | TerminatorKind::UbCheck { .. } => {} } self.check_for_move(trans, loc); diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index ccf3dc7941fed..dab59086df4a3 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -432,6 +432,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { fn gather_terminator(&mut self, term: &Terminator<'tcx>) { match term.kind { TerminatorKind::Goto { target: _ } + | TerminatorKind::UbCheck { .. } | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } // In some sense returning moves the return place into the current diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 025d2ddfd4ff7..8a095ecd8bf8e 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -276,7 +276,8 @@ pub trait ValueAnalysis<'tcx> { | TerminatorKind::Assert { .. } | TerminatorKind::CoroutineDrop | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } => { + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::UbCheck { .. } => { // These terminators have no effect on the analysis. } } diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index 28765af20ad3b..f1eaf6a18688e 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -1,13 +1,9 @@ use crate::MirPass; -use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_index::IndexVec; +use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::mir::{ - interpret::Scalar, - visit::{PlaceContext, Visitor}, -}; -use rustc_middle::ty::{Ty, TyCtxt, TypeAndMut}; +use rustc_middle::ty::TyCtxt; use rustc_session::Session; pub struct CheckAlignment; @@ -38,25 +34,19 @@ impl<'tcx> MirPass<'tcx> for CheckAlignment { let statement = &basic_blocks[block].statements[statement_index]; let source_info = statement.source_info; - let mut finder = PointerFinder { - local_decls, - tcx, - pointers: Vec::new(), - def_id: body.source.def_id(), - }; - for (pointer, pointee_ty) in finder.find_pointers(statement) { + let mut finder = PointerFinder { local_decls, tcx, pointers: Vec::new() }; + for pointer in finder.find_pointers(statement) { debug!("Inserting alignment check for {:?}", pointer.ty(&*local_decls, tcx).ty); let new_block = split_block(basic_blocks, location); - insert_alignment_check( - tcx, - local_decls, - &mut basic_blocks[block], - pointer, - pointee_ty, + + basic_blocks[block].terminator = Some(Terminator { source_info, - new_block, - ); + kind: TerminatorKind::UbCheck { + target: new_block, + kind: UbCheckKind::PointerAlignment { pointer: Operand::Copy(pointer) }, + }, + }); } } } @@ -64,7 +54,7 @@ impl<'tcx> MirPass<'tcx> for CheckAlignment { } impl<'tcx, 'a> PointerFinder<'tcx, 'a> { - fn find_pointers(&mut self, statement: &Statement<'tcx>) -> Vec<(Place<'tcx>, Ty<'tcx>)> { + fn find_pointers(&mut self, statement: &Statement<'tcx>) -> Vec> { self.pointers.clear(); self.visit_statement(statement, Location::START); core::mem::take(&mut self.pointers) @@ -74,8 +64,7 @@ impl<'tcx, 'a> PointerFinder<'tcx, 'a> { struct PointerFinder<'tcx, 'a> { local_decls: &'a mut LocalDecls<'tcx>, tcx: TyCtxt<'tcx>, - def_id: DefId, - pointers: Vec<(Place<'tcx>, Ty<'tcx>)>, + pointers: Vec>, } impl<'tcx, 'a> Visitor<'tcx> for PointerFinder<'tcx, 'a> { @@ -113,11 +102,6 @@ impl<'tcx, 'a> Visitor<'tcx> for PointerFinder<'tcx, 'a> { pointee_ty = pointee_ty.sequence_element_type(self.tcx); } - if !pointee_ty.is_sized(self.tcx, self.tcx.param_env_reveal_all_normalized(self.def_id)) { - debug!("Unsafe pointer, but unsized: {:?}", pointer_ty); - return; - } - if [self.tcx.types.bool, self.tcx.types.i8, self.tcx.types.u8, self.tcx.types.str_] .contains(&pointee_ty) { @@ -125,7 +109,7 @@ impl<'tcx, 'a> Visitor<'tcx> for PointerFinder<'tcx, 'a> { return; } - self.pointers.push((pointer, pointee_ty)) + self.pointers.push(pointer) } } @@ -144,100 +128,3 @@ fn split_block( basic_blocks.push(new_block) } - -fn insert_alignment_check<'tcx>( - tcx: TyCtxt<'tcx>, - local_decls: &mut IndexVec>, - block_data: &mut BasicBlockData<'tcx>, - pointer: Place<'tcx>, - pointee_ty: Ty<'tcx>, - source_info: SourceInfo, - new_block: BasicBlock, -) { - // Cast the pointer to a *const () - let const_raw_ptr = Ty::new_ptr(tcx, TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not }); - let rvalue = Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(pointer), const_raw_ptr); - let thin_ptr = local_decls.push(LocalDecl::with_source_info(const_raw_ptr, source_info)).into(); - block_data - .statements - .push(Statement { source_info, kind: StatementKind::Assign(Box::new((thin_ptr, rvalue))) }); - - // Transmute the pointer to a usize (equivalent to `ptr.addr()`) - let rvalue = Rvalue::Cast(CastKind::Transmute, Operand::Copy(thin_ptr), tcx.types.usize); - let addr = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); - block_data - .statements - .push(Statement { source_info, kind: StatementKind::Assign(Box::new((addr, rvalue))) }); - - // Get the alignment of the pointee - let alignment = - local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); - let rvalue = Rvalue::NullaryOp(NullOp::AlignOf, pointee_ty); - block_data.statements.push(Statement { - source_info, - kind: StatementKind::Assign(Box::new((alignment, rvalue))), - }); - - // Subtract 1 from the alignment to get the alignment mask - let alignment_mask = - local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); - let one = Operand::Constant(Box::new(ConstOperand { - span: source_info.span, - user_ty: None, - const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(1, &tcx)), tcx.types.usize), - })); - block_data.statements.push(Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - alignment_mask, - Rvalue::BinaryOp(BinOp::Sub, Box::new((Operand::Copy(alignment), one))), - ))), - }); - - // BitAnd the alignment mask with the pointer - let alignment_bits = - local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); - block_data.statements.push(Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - alignment_bits, - Rvalue::BinaryOp( - BinOp::BitAnd, - Box::new((Operand::Copy(addr), Operand::Copy(alignment_mask))), - ), - ))), - }); - - // Check if the alignment bits are all zero - let is_ok = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into(); - let zero = Operand::Constant(Box::new(ConstOperand { - span: source_info.span, - user_ty: None, - const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)), tcx.types.usize), - })); - block_data.statements.push(Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - is_ok, - Rvalue::BinaryOp(BinOp::Eq, Box::new((Operand::Copy(alignment_bits), zero.clone()))), - ))), - }); - - // Set this block's terminator to our assert, continuing to new_block if we pass - block_data.terminator = Some(Terminator { - source_info, - kind: TerminatorKind::Assert { - cond: Operand::Copy(is_ok), - expected: true, - target: new_block, - msg: Box::new(AssertKind::MisalignedPointerDereference { - required: Operand::Copy(alignment), - found: Operand::Copy(addr), - }), - // This calls panic_misaligned_pointer_dereference, which is #[rustc_nounwind]. - // We never want to insert an unwind into unsafe code, because unwinding could - // make a failing UB check turn into much worse UB when we start unwinding. - unwind: UnwindAction::Unreachable, - }, - }); -} diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index 8872f9a97d746..ca28fee121eda 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -62,7 +62,8 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } => { + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::UbCheck { .. } => { // safe (at least as emitted during MIR construction) } diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index a23ba9c4aa9fd..8f9704e13b7d1 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -652,7 +652,8 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::Call { .. } - | TerminatorKind::InlineAsm { .. } => {} + | TerminatorKind::InlineAsm { .. } + | TerminatorKind::UbCheck { .. } => {} } self.worklist.extend(terminator.successors()); diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index fc30a718cbb57..ad9560adc9dc9 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1238,7 +1238,8 @@ fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool { | TerminatorKind::Unreachable | TerminatorKind::CoroutineDrop | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } => {} + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::UbCheck { .. } => {} // Resume will *continue* unwinding, but if there's no other unwinding terminator it // will never be reached. @@ -1761,7 +1762,8 @@ impl<'tcx> Visitor<'tcx> for EnsureCoroutineFieldAssignmentsNeverAlias<'_> { | TerminatorKind::Assert { .. } | TerminatorKind::CoroutineDrop | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } => {} + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::UbCheck { .. } => {} } } } diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 6bab62aa85409..ac172ec7f9d61 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -151,7 +151,8 @@ impl CoverageGraph { | TerminatorKind::Assert { .. } | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::InlineAsm { .. } => {} + | TerminatorKind::InlineAsm { .. } + | TerminatorKind::UbCheck { .. } => {} } } diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 6189e5379ea05..2dcbf62cedc64 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -151,7 +151,8 @@ fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option { | TerminatorKind::SwitchInt { .. } // For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`. | TerminatorKind::FalseEdge { .. } - | TerminatorKind::Goto { .. } => None, + | TerminatorKind::Goto { .. } | + TerminatorKind::UbCheck { .. } => None, // Call `func` operand can have a more specific span when part of a chain of calls | TerminatorKind::Call { ref func, .. } => { diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 15502adfb5aad..54165354fab68 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -142,7 +142,7 @@ use rustc_middle::mir::HasLocalDecls; use rustc_middle::mir::{dump_mir, PassWhere}; use rustc_middle::mir::{ traversal, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place, Rvalue, - Statement, StatementKind, TerminatorKind, + Statement, StatementKind, TerminatorKind, UbCheckKind, }; use rustc_middle::ty::TyCtxt; use rustc_mir_dataflow::impls::MaybeLiveLocals; @@ -611,7 +611,11 @@ impl WriteInfo { self.reset(); match terminator { TerminatorKind::SwitchInt { discr: op, .. } - | TerminatorKind::Assert { cond: op, .. } => { + | TerminatorKind::Assert { cond: op, .. } + | TerminatorKind::UbCheck { + target: _, + kind: UbCheckKind::PointerAlignment { pointer: op }, + } => { self.add_operand(op); } TerminatorKind::Call { destination, func, args, .. } => { diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 793dcf0d994c3..5c3838d39ba8b 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -934,7 +934,8 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { match terminator.kind { TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } => bug!(), - TerminatorKind::Goto { ref mut target } => { + TerminatorKind::Goto { ref mut target } + | TerminatorKind::UbCheck { ref mut target, .. } => { *target = self.map_block(*target); } TerminatorKind::SwitchInt { ref mut targets, .. } => { diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 7b918be447413..5394d7ef9f52a 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -519,7 +519,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { // `SwitchInt` is handled specially. TerminatorKind::SwitchInt { .. } => return, // We can recurse, no thing particular to do. - TerminatorKind::Goto { .. } => None, + TerminatorKind::Goto { .. } | TerminatorKind::UbCheck { .. } => None, // Flood the overwritten place, and progress through. TerminatorKind::Drop { place: destination, .. } | TerminatorKind::Call { destination, .. } => Some(destination), diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs index 54892442c87b2..52a47369ce556 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -66,7 +66,8 @@ impl RemoveNoopLandingPads { | TerminatorKind::UnwindResume | TerminatorKind::SwitchInt { .. } | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } => { + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::UbCheck { .. } => { terminator.successors().all(|succ| nop_landing_pads.contains(succ)) } TerminatorKind::CoroutineDrop diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs index 907cfe7581a8d..44c0fc4dd560f 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -99,7 +99,9 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize { match &predecessor.terminator().kind { // The following terminators are // unconditionally valid - TerminatorKind::Goto { .. } | TerminatorKind::SwitchInt { .. } => {} + TerminatorKind::Goto { .. } + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::UbCheck { .. } => {} TerminatorKind::FalseEdge { real_target, .. } => { if *real_target != block_id { @@ -147,7 +149,8 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize { let terminator = blocks[pred_id].terminator_mut(); match terminator.kind { - TerminatorKind::Goto { ref mut target } => { + TerminatorKind::Goto { ref mut target } + | TerminatorKind::UbCheck { ref mut target, .. } => { *target = new_block_id; } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 82fee7c8dfe58..2db663eccdc7c 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -854,7 +854,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { | mir::TerminatorKind::SwitchInt { .. } | mir::TerminatorKind::UnwindResume | mir::TerminatorKind::Return - | mir::TerminatorKind::Unreachable => {} + | mir::TerminatorKind::Unreachable + | mir::TerminatorKind::UbCheck { .. } => {} mir::TerminatorKind::CoroutineDrop | mir::TerminatorKind::Yield { .. } | mir::TerminatorKind::FalseEdge { .. } diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index b619ce6e35f99..ba58d790e9f18 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -1010,6 +1010,7 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> { destination: destination.map(|d| d.as_usize()), unwind: unwind.stable(tables), }, + mir::TerminatorKind::UbCheck { .. } => TerminatorKind::UbCheck, mir::TerminatorKind::Yield { .. } | mir::TerminatorKind::CoroutineDrop | mir::TerminatorKind::FalseEdge { .. } diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 804f5e3d9d0c4..3a2cd4f651504 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -120,6 +120,7 @@ pub enum TerminatorKind { destination: Option, unwind: UnwindAction, }, + UbCheck, } #[derive(Clone, Debug, Eq, PartialEq)] diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index 806dced71ff3e..171d3748a01c8 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -254,6 +254,7 @@ pub trait MirVisitor { TerminatorKind::SwitchInt { discr, targets: _, otherwise: _ } => { self.visit_operand(discr, location); } + TerminatorKind::UbCheck => {} } } diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index ef0e2d3e1b3d1..87cd88ff0f46b 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -295,7 +295,8 @@ fn check_terminator<'tcx>( | TerminatorKind::Return | TerminatorKind::UnwindResume | TerminatorKind::UnwindTerminate(_) - | TerminatorKind::Unreachable => Ok(()), + | TerminatorKind::Unreachable | + TerminatorKind::UbCheck { .. } => Ok(()), TerminatorKind::Drop { place, .. } => { if !is_ty_const_destruct(tcx, place.ty(&body.local_decls, tcx).ty, body) { return Err((