]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/coherence/unsafety.rs
Rollup merge of #69387 - petrochenkov:idprint, r=Mark-Simulacrum
[rust.git] / src / librustc_typeck / 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::ty::TyCtxt;
5 use rustc_errors::struct_span_err;
6 use rustc_hir as hir;
7 use rustc_hir::itemlikevisit::ItemLikeVisitor;
8 use rustc_hir::Unsafety;
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         let local_did = self.tcx.hir().local_def_id(item.hir_id);
28         if let Some(trait_ref) = self.tcx.impl_trait_ref(local_did) {
29             let trait_def = self.tcx.trait_def(trait_ref.def_id);
30             let unsafe_attr = impl_generics.and_then(|generics| {
31                 generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle")
32             });
33             match (trait_def.unsafety, unsafe_attr, unsafety, polarity) {
34                 (Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
35                     struct_span_err!(
36                         self.tcx.sess,
37                         item.span,
38                         E0199,
39                         "implementing the trait `{}` is not unsafe",
40                         trait_ref.print_only_trait_path()
41                     )
42                     .emit();
43                 }
44
45                 (Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
46                     struct_span_err!(
47                         self.tcx.sess,
48                         item.span,
49                         E0200,
50                         "the trait `{}` requires an `unsafe impl` declaration",
51                         trait_ref.print_only_trait_path()
52                     )
53                     .emit();
54                 }
55
56                 (
57                     Unsafety::Normal,
58                     Some(attr_name),
59                     Unsafety::Normal,
60                     hir::ImplPolarity::Positive,
61                 ) => {
62                     struct_span_err!(
63                         self.tcx.sess,
64                         item.span,
65                         E0569,
66                         "requires an `unsafe impl` declaration due to `#[{}]` attribute",
67                         attr_name
68                     )
69                     .emit();
70                 }
71
72                 (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative) => {
73                     // Reported in AST validation
74                     self.tcx.sess.delay_span_bug(item.span, "unsafe negative impl");
75                 }
76                 (_, _, Unsafety::Normal, hir::ImplPolarity::Negative)
77                 | (Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive)
78                 | (Unsafety::Normal, Some(_), Unsafety::Unsafe, hir::ImplPolarity::Positive)
79                 | (Unsafety::Normal, None, Unsafety::Normal, _) => {
80                     // OK
81                 }
82             }
83         }
84     }
85 }
86
87 impl ItemLikeVisitor<'v> for UnsafetyChecker<'tcx> {
88     fn visit_item(&mut self, item: &'v hir::Item<'v>) {
89         if let hir::ItemKind::Impl { unsafety, polarity, ref generics, .. } = item.kind {
90             self.check_unsafety_coherence(item, Some(generics), unsafety, polarity);
91         }
92     }
93
94     fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
95
96     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
97 }