Skip to main content

rustc_hir_analysis/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
4use 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 `Self` has unsafe fields, `Copy` is unsafe to implement.
27        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            // Reported in AST validation
115            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}