]>
Commit | Line | Data |
---|---|---|
04454e1e | 1 | use rustc_hir::def_id::LocalDefId; |
f9f354fc XL |
2 | use rustc_middle::mir::visit::{PlaceContext, Visitor}; |
3 | use rustc_middle::mir::*; | |
cdc7bbd5 | 4 | use rustc_middle::ty::query::Providers; |
f9f354fc XL |
5 | use rustc_middle::ty::{self, TyCtxt}; |
6 | use rustc_session::lint::builtin::UNALIGNED_REFERENCES; | |
7 | ||
f9f354fc | 8 | use crate::util; |
a2a8927a | 9 | use crate::MirLint; |
f9f354fc | 10 | |
cdc7bbd5 XL |
11 | pub(crate) fn provide(providers: &mut Providers) { |
12 | *providers = Providers { unsafe_derive_on_repr_packed, ..*providers }; | |
13 | } | |
14 | ||
f9f354fc XL |
15 | pub struct CheckPackedRef; |
16 | ||
a2a8927a XL |
17 | impl<'tcx> MirLint<'tcx> for CheckPackedRef { |
18 | fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { | |
29967ef6 | 19 | let param_env = tcx.param_env(body.source.def_id()); |
f9f354fc XL |
20 | let source_info = SourceInfo::outermost(body.span); |
21 | let mut checker = PackedRefChecker { body, tcx, param_env, source_info }; | |
22 | checker.visit_body(&body); | |
23 | } | |
24 | } | |
25 | ||
26 | struct PackedRefChecker<'a, 'tcx> { | |
27 | body: &'a Body<'tcx>, | |
28 | tcx: TyCtxt<'tcx>, | |
29 | param_env: ty::ParamEnv<'tcx>, | |
30 | source_info: SourceInfo, | |
31 | } | |
32 | ||
cdc7bbd5 XL |
33 | fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) { |
34 | let lint_hir_id = tcx.hir().local_def_id_to_hir_id(def_id); | |
35 | ||
2b03887a FG |
36 | // FIXME: when we make this a hard error, this should have its |
37 | // own error code. | |
38 | ||
39 | let extra = if tcx.generics_of(def_id).own_requires_monomorphization() { | |
40 | "with type or const parameters" | |
41 | } else { | |
42 | "that does not derive `Copy`" | |
43 | }; | |
44 | let message = format!( | |
45 | "`{}` can't be derived on this `#[repr(packed)]` struct {}", | |
46 | tcx.item_name(tcx.trait_id_of_impl(def_id.to_def_id()).expect("derived trait name")), | |
47 | extra | |
48 | ); | |
49 | ||
50 | tcx.struct_span_lint_hir( | |
51 | UNALIGNED_REFERENCES, | |
52 | lint_hir_id, | |
53 | tcx.def_span(def_id), | |
54 | message, | |
55 | |lint| lint, | |
56 | ); | |
cdc7bbd5 XL |
57 | } |
58 | ||
a2a8927a | 59 | impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> { |
f9f354fc XL |
60 | fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { |
61 | // Make sure we know where in the MIR we are. | |
62 | self.source_info = terminator.source_info; | |
63 | self.super_terminator(terminator, location); | |
64 | } | |
65 | ||
66 | fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { | |
67 | // Make sure we know where in the MIR we are. | |
68 | self.source_info = statement.source_info; | |
69 | self.super_statement(statement, location); | |
70 | } | |
71 | ||
72 | fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { | |
73 | if context.is_borrow() { | |
74 | if util::is_disaligned(self.tcx, self.body, self.param_env, *place) { | |
cdc7bbd5 | 75 | let def_id = self.body.source.instance.def_id(); |
04454e1e FG |
76 | if let Some(impl_def_id) = self |
77 | .tcx | |
78 | .impl_of_method(def_id) | |
79 | .filter(|&def_id| self.tcx.is_builtin_derive(def_id)) | |
80 | { | |
cdc7bbd5 XL |
81 | // If a method is defined in the local crate, |
82 | // the impl containing that method should also be. | |
83 | self.tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id.expect_local()); | |
84 | } else { | |
85 | let source_info = self.source_info; | |
86 | let lint_root = self.body.source_scopes[source_info.scope] | |
87 | .local_data | |
88 | .as_ref() | |
89 | .assert_crate_local() | |
90 | .lint_root; | |
91 | self.tcx.struct_span_lint_hir( | |
92 | UNALIGNED_REFERENCES, | |
93 | lint_root, | |
94 | source_info.span, | |
2b03887a | 95 | "reference to packed field is unaligned", |
cdc7bbd5 | 96 | |lint| { |
2b03887a | 97 | lint |
cdc7bbd5 XL |
98 | .note( |
99 | "fields of packed structs are not properly aligned, and creating \ | |
100 | a misaligned reference is undefined behavior (even if that \ | |
101 | reference is never dereferenced)", | |
102 | ) | |
a2a8927a XL |
103 | .help( |
104 | "copy the field contents to a local variable, or replace the \ | |
105 | reference with a raw pointer and use `read_unaligned`/`write_unaligned` \ | |
106 | (loads and stores via `*p` must be properly aligned even when using raw pointers)" | |
107 | ) | |
cdc7bbd5 XL |
108 | }, |
109 | ); | |
110 | } | |
f9f354fc XL |
111 | } |
112 | } | |
113 | } | |
114 | } |