rustc_hir_analysis/coherence/
unsafety.rs
1use rustc_errors::codes::*;
5use rustc_errors::struct_span_code_err;
6use rustc_hir::{LangItem, Safety};
7use rustc_middle::ty::ImplPolarity::*;
8use rustc_middle::ty::print::PrintTraitRefExt as _;
9use rustc_middle::ty::{ImplTraitHeader, TraitDef, TyCtxt};
10use rustc_span::ErrorGuaranteed;
11use rustc_span::def_id::LocalDefId;
12
13pub(super) fn check_item(
14 tcx: TyCtxt<'_>,
15 def_id: LocalDefId,
16 trait_header: ImplTraitHeader<'_>,
17 trait_def: &TraitDef,
18) -> Result<(), ErrorGuaranteed> {
19 let unsafe_attr =
20 tcx.generics_of(def_id).own_params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
21 let trait_ref = trait_header.trait_ref.instantiate_identity();
22
23 let is_copy = tcx.is_lang_item(trait_def.def_id, LangItem::Copy);
24 let trait_def_safety = if is_copy {
25 if trait_header.trait_ref.skip_binder().self_ty().has_unsafe_fields() {
27 rustc_hir::Safety::Unsafe
28 } else {
29 rustc_hir::Safety::Safe
30 }
31 } else {
32 trait_def.safety
33 };
34
35 match (trait_def_safety, unsafe_attr, trait_header.safety, trait_header.polarity) {
36 (Safety::Safe, None, Safety::Unsafe, Positive | Reservation) => {
37 let span = tcx.def_span(def_id);
38 return Err(struct_span_code_err!(
39 tcx.dcx(),
40 tcx.def_span(def_id),
41 E0199,
42 "implementing the trait `{}` is not unsafe",
43 trait_ref.print_trait_sugared()
44 )
45 .with_span_suggestion_verbose(
46 span.with_hi(span.lo() + rustc_span::BytePos(7)),
47 "remove `unsafe` from this trait implementation",
48 "",
49 rustc_errors::Applicability::MachineApplicable,
50 )
51 .emit());
52 }
53
54 (Safety::Unsafe, _, Safety::Safe, Positive | Reservation) => {
55 let span = tcx.def_span(def_id);
56 return Err(struct_span_code_err!(
57 tcx.dcx(),
58 span,
59 E0200,
60 "the trait `{}` requires an `unsafe impl` declaration",
61 trait_ref.print_trait_sugared()
62 )
63 .with_note(if is_copy {
64 format!(
65 "the trait `{}` cannot be safely implemented for `{}` \
66 because it has unsafe fields. Review the invariants \
67 of those fields before adding an `unsafe impl`",
68 trait_ref.print_trait_sugared(),
69 trait_ref.self_ty(),
70 )
71 } else {
72 format!(
73 "the trait `{}` enforces invariants that the compiler can't check. \
74 Review the trait documentation and make sure this implementation \
75 upholds those invariants before adding the `unsafe` keyword",
76 trait_ref.print_trait_sugared()
77 )
78 })
79 .with_span_suggestion_verbose(
80 span.shrink_to_lo(),
81 "add `unsafe` to this trait implementation",
82 "unsafe ",
83 rustc_errors::Applicability::MaybeIncorrect,
84 )
85 .emit());
86 }
87
88 (Safety::Safe, Some(attr_name), Safety::Safe, Positive | Reservation) => {
89 let span = tcx.def_span(def_id);
90 return Err(struct_span_code_err!(
91 tcx.dcx(),
92 span,
93 E0569,
94 "requires an `unsafe impl` declaration due to `#[{}]` attribute",
95 attr_name
96 )
97 .with_note(format!(
98 "the trait `{}` enforces invariants that the compiler can't check. \
99 Review the trait documentation and make sure this implementation \
100 upholds those invariants before adding the `unsafe` keyword",
101 trait_ref.print_trait_sugared()
102 ))
103 .with_span_suggestion_verbose(
104 span.shrink_to_lo(),
105 "add `unsafe` to this trait implementation",
106 "unsafe ",
107 rustc_errors::Applicability::MaybeIncorrect,
108 )
109 .emit());
110 }
111
112 (_, _, Safety::Unsafe, Negative) => {
113 assert!(tcx.dcx().has_errors().is_some(), "unsafe negative impl");
115 Ok(())
116 }
117 (_, _, Safety::Safe, Negative)
118 | (Safety::Unsafe, _, Safety::Unsafe, Positive | Reservation)
119 | (Safety::Safe, Some(_), Safety::Unsafe, Positive | Reservation)
120 | (Safety::Safe, None, Safety::Safe, _) => Ok(()),
121 }
122}