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