Skip to main content

rustc_mir_transform/
check_packed_ref.rs

1use rustc_middle::mir::visit::{PlaceContext, Visitor};
2use rustc_middle::mir::*;
3use rustc_middle::ty::{self, TyCtxt};
4use rustc_span::span_bug;
5
6use crate::{diagnostics, util};
7
8pub(super) struct CheckPackedRef;
9
10impl<'tcx> crate::MirLint<'tcx> for CheckPackedRef {
11    fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
12        let typing_env = body.typing_env(tcx);
13        let mut checker = PackedRefChecker { body, tcx, typing_env };
14        for (bb, data) in body.basic_blocks.iter_enumerated() {
15            checker.visit_basic_block_data(bb, data);
16        }
17    }
18}
19
20struct PackedRefChecker<'a, 'tcx> {
21    body: &'a Body<'tcx>,
22    tcx: TyCtxt<'tcx>,
23    typing_env: ty::TypingEnv<'tcx>,
24}
25
26impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
27    fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
28        if context.is_borrow()
29            && let Some((adt, pack)) =
30                util::place_unalignment(self.tcx, self.body, self.typing_env, *place)
31        {
32            let source_info = self.body.source_info(location);
33            let def_id = self.body.source.instance.def_id();
34            if let Some(impl_def_id) = self.tcx.trait_impl_of_assoc(def_id)
35                && self.tcx.is_builtin_derived(impl_def_id)
36            {
37                // If we ever reach here it means that the generated derive
38                // code is somehow doing an unaligned reference, which it
39                // shouldn't do.
40                span_bug!(source_info.span, "builtin derive created an unaligned reference");
41            } else {
42                self.tcx.dcx().emit_err(diagnostics::UnalignedPackedRef {
43                    span: source_info.span,
44                    ty_descr: adt.descr(),
45                    align: pack.bytes(),
46                });
47            }
48        }
49    }
50}