//! Unsafety checker: every impl either implements a trait defined in this //! crate or pertains to a type defined in this crate. use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir::Safety; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{ImplPolarity::*, ImplTraitHeader, TraitDef, TyCtxt}; use rustc_span::def_id::LocalDefId; use rustc_span::ErrorGuaranteed; pub(super) fn check_item( tcx: TyCtxt<'_>, def_id: LocalDefId, trait_header: ImplTraitHeader<'_>, trait_def: &TraitDef, ) -> Result<(), ErrorGuaranteed> { let unsafe_attr = tcx.generics_of(def_id).own_params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle"); let trait_ref = trait_header.trait_ref.instantiate_identity(); match (trait_def.safety, unsafe_attr, trait_header.safety, trait_header.polarity) { (Safety::Safe, None, Safety::Unsafe, Positive | Reservation) => { let span = tcx.def_span(def_id); return Err(struct_span_code_err!( tcx.dcx(), tcx.def_span(def_id), E0199, "implementing the trait `{}` is not unsafe", trait_ref.print_trait_sugared() ) .with_span_suggestion_verbose( span.with_hi(span.lo() + rustc_span::BytePos(7)), "remove `unsafe` from this trait implementation", "", rustc_errors::Applicability::MachineApplicable, ) .emit()); } (Safety::Unsafe, _, Safety::Safe, Positive | Reservation) => { let span = tcx.def_span(def_id); return Err(struct_span_code_err!( tcx.dcx(), span, E0200, "the trait `{}` requires an `unsafe impl` declaration", trait_ref.print_trait_sugared() ) .with_note(format!( "the trait `{}` 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() )) .with_span_suggestion_verbose( span.shrink_to_lo(), "add `unsafe` to this trait implementation", "unsafe ", rustc_errors::Applicability::MaybeIncorrect, ) .emit()); } (Safety::Safe, Some(attr_name), Safety::Safe, Positive | Reservation) => { let span = tcx.def_span(def_id); return Err(struct_span_code_err!( tcx.dcx(), span, E0569, "requires an `unsafe impl` declaration due to `#[{}]` attribute", attr_name ) .with_note(format!( "the trait `{}` 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() )) .with_span_suggestion_verbose( span.shrink_to_lo(), "add `unsafe` to this trait implementation", "unsafe ", rustc_errors::Applicability::MaybeIncorrect, ) .emit()); } (_, _, Safety::Unsafe, Negative) => { // Reported in AST validation assert!(tcx.dcx().has_errors().is_some(), "unsafe negative impl"); Ok(()) } (_, _, Safety::Safe, Negative) | (Safety::Unsafe, _, Safety::Unsafe, Positive | Reservation) | (Safety::Safe, Some(_), Safety::Unsafe, Positive | Reservation) | (Safety::Safe, None, Safety::Safe, _) => Ok(()), } }