]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_typeck/src/coherence/unsafety.rs
Rollup merge of #87727 - SkiFire13:fix-87718, r=jackh726
[rust.git] / compiler / rustc_typeck / src / coherence / unsafety.rs
1 //! Unsafety checker: every impl either implements a trait defined in this
2 //! crate or pertains to a type defined in this crate.
3
4 use rustc_errors::struct_span_err;
5 use rustc_hir as hir;
6 use rustc_hir::itemlikevisit::ItemLikeVisitor;
7 use rustc_hir::Unsafety;
8 use rustc_middle::ty::TyCtxt;
9
10 pub fn check(tcx: TyCtxt<'_>) {
11     let mut unsafety = UnsafetyChecker { tcx };
12     tcx.hir().krate().visit_all_item_likes(&mut unsafety);
13 }
14
15 struct UnsafetyChecker<'tcx> {
16     tcx: TyCtxt<'tcx>,
17 }
18
19 impl UnsafetyChecker<'tcx> {
20     fn check_unsafety_coherence(
21         &mut self,
22         item: &'v hir::Item<'v>,
23         impl_generics: Option<&hir::Generics<'_>>,
24         unsafety: hir::Unsafety,
25         polarity: hir::ImplPolarity,
26     ) {
27         if let Some(trait_ref) = self.tcx.impl_trait_ref(item.def_id) {
28             let trait_def = self.tcx.trait_def(trait_ref.def_id);
29             let unsafe_attr = impl_generics.and_then(|generics| {
30                 generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle")
31             });
32             match (trait_def.unsafety, unsafe_attr, unsafety, polarity) {
33                 (Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
34                     struct_span_err!(
35                         self.tcx.sess,
36                         item.span,
37                         E0199,
38                         "implementing the trait `{}` is not unsafe",
39                         trait_ref.print_only_trait_path()
40                     )
41                     .emit();
42                 }
43
44                 (Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
45                     struct_span_err!(
46                         self.tcx.sess,
47                         item.span,
48                         E0200,
49                         "the trait `{}` requires an `unsafe impl` declaration",
50                         trait_ref.print_only_trait_path()
51                     )
52                     .emit();
53                 }
54
55                 (
56                     Unsafety::Normal,
57                     Some(attr_name),
58                     Unsafety::Normal,
59                     hir::ImplPolarity::Positive,
60                 ) => {
61                     struct_span_err!(
62                         self.tcx.sess,
63                         item.span,
64                         E0569,
65                         "requires an `unsafe impl` declaration due to `#[{}]` attribute",
66                         attr_name
67                     )
68                     .emit();
69                 }
70
71                 (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => {
72                     // Reported in AST validation
73                     self.tcx.sess.delay_span_bug(item.span, "unsafe negative impl");
74                 }
75                 (_, _, Unsafety::Normal, hir::ImplPolarity::Negative(_))
76                 | (Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive)
77                 | (Unsafety::Normal, Some(_), Unsafety::Unsafe, hir::ImplPolarity::Positive)
78                 | (Unsafety::Normal, None, Unsafety::Normal, _) => {
79                     // OK
80                 }
81             }
82         }
83     }
84 }
85
86 impl ItemLikeVisitor<'v> for UnsafetyChecker<'tcx> {
87     fn visit_item(&mut self, item: &'v hir::Item<'v>) {
88         if let hir::ItemKind::Impl(ref impl_) = item.kind {
89             self.check_unsafety_coherence(
90                 item,
91                 Some(&impl_.generics),
92                 impl_.unsafety,
93                 impl_.polarity,
94             );
95         }
96     }
97
98     fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
99
100     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
101
102     fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
103 }