]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_hir_analysis/src/coherence/unsafety.rs
Merge commit '7f27e2e74ef957baa382dc05cf08df6368165c74' into clippyup
[rust.git] / compiler / rustc_hir_analysis / 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::def::DefKind;
7 use rustc_hir::Unsafety;
8 use rustc_middle::ty::TyCtxt;
9 use rustc_span::def_id::LocalDefId;
10
11 pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
12     debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Impl));
13     let item = tcx.hir().expect_item(def_id);
14     let hir::ItemKind::Impl(ref impl_) = item.kind else { bug!() };
15
16     if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
17         let trait_def = tcx.trait_def(trait_ref.def_id);
18         let unsafe_attr =
19             impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
20         match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) {
21             (Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
22                 struct_span_err!(
23                     tcx.sess,
24                     tcx.def_span(def_id),
25                     E0199,
26                     "implementing the trait `{}` is not unsafe",
27                     trait_ref.print_only_trait_path()
28                 )
29                 .span_suggestion_verbose(
30                     item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)),
31                     "remove `unsafe` from this trait implementation",
32                     "",
33                     rustc_errors::Applicability::MachineApplicable,
34                 )
35                 .emit();
36             }
37
38             (Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
39                 struct_span_err!(
40                     tcx.sess,
41                     tcx.def_span(def_id),
42                     E0200,
43                     "the trait `{}` requires an `unsafe impl` declaration",
44                     trait_ref.print_only_trait_path()
45                 )
46                 .note(format!(
47                     "the trait `{}` enforces invariants that the compiler can't check. \
48                     Review the trait documentation and make sure this implementation \
49                     upholds those invariants before adding the `unsafe` keyword",
50                     trait_ref.print_only_trait_path()
51                 ))
52                 .span_suggestion_verbose(
53                     item.span.shrink_to_lo(),
54                     "add `unsafe` to this trait implementation",
55                     "unsafe ",
56                     rustc_errors::Applicability::MaybeIncorrect,
57                 )
58                 .emit();
59             }
60
61             (Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => {
62                 struct_span_err!(
63                     tcx.sess,
64                     tcx.def_span(def_id),
65                     E0569,
66                     "requires an `unsafe impl` declaration due to `#[{}]` attribute",
67                     attr_name
68                 )
69                 .note(format!(
70                     "the trait `{}` enforces invariants that the compiler can't check. \
71                     Review the trait documentation and make sure this implementation \
72                     upholds those invariants before adding the `unsafe` keyword",
73                     trait_ref.print_only_trait_path()
74                 ))
75                 .span_suggestion_verbose(
76                     item.span.shrink_to_lo(),
77                     "add `unsafe` to this trait implementation",
78                     "unsafe ",
79                     rustc_errors::Applicability::MaybeIncorrect,
80                 )
81                 .emit();
82             }
83
84             (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => {
85                 // Reported in AST validation
86                 tcx.sess.delay_span_bug(item.span, "unsafe negative impl");
87             }
88             (_, _, Unsafety::Normal, hir::ImplPolarity::Negative(_))
89             | (Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive)
90             | (Unsafety::Normal, Some(_), Unsafety::Unsafe, hir::ImplPolarity::Positive)
91             | (Unsafety::Normal, None, Unsafety::Normal, _) => {
92                 // OK
93             }
94         }
95     }
96 }