diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index a71ea00a0448e..60e1e6d5f877d 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -131,7 +131,7 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed> res = res.and(check_impl(tcx, impl_def_id, trait_ref)); res = res.and(check_object_overlap(tcx, impl_def_id, trait_ref)); - res = res.and(unsafety::check_item(tcx, impl_def_id)); + res = res.and(unsafety::check_item(tcx, impl_def_id, trait_ref)); res = res.and(tcx.ensure().orphan_check_impl(impl_def_id)); res = res.and(builtin::check_trait(tcx, def_id, impl_def_id)); } diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index e3b5c724cdee2..d217d53587d56 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -4,94 +4,91 @@ use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::Unsafety; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{TraitRef, TyCtxt}; use rustc_span::def_id::LocalDefId; use rustc_span::ErrorGuaranteed; -pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> { +pub(super) fn check_item( + tcx: TyCtxt<'_>, + def_id: LocalDefId, + trait_ref: TraitRef<'_>, +) -> Result<(), ErrorGuaranteed> { let item = tcx.hir().expect_item(def_id); let impl_ = item.expect_impl(); + let trait_def = tcx.trait_def(trait_ref.def_id); + let unsafe_attr = impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle"); + match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) { + (Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => { + 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( + item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)), + "remove `unsafe` from this trait implementation", + "", + rustc_errors::Applicability::MachineApplicable, + ) + .emit()); + } - if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) { - let trait_ref = trait_ref.instantiate_identity(); - let trait_def = tcx.trait_def(trait_ref.def_id); - let unsafe_attr = - impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle"); - match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) { - (Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => { - 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( - item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)), - "remove `unsafe` from this trait implementation", - "", - rustc_errors::Applicability::MachineApplicable, - ) - .emit()); - } - - (Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => { - return Err(struct_span_code_err!( - tcx.dcx(), - tcx.def_span(def_id), - 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. \ + (Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => { + return Err(struct_span_code_err!( + tcx.dcx(), + tcx.def_span(def_id), + 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( - item.span.shrink_to_lo(), - "add `unsafe` to this trait implementation", - "unsafe ", - rustc_errors::Applicability::MaybeIncorrect, - ) - .emit()); - } + trait_ref.print_trait_sugared() + )) + .with_span_suggestion_verbose( + item.span.shrink_to_lo(), + "add `unsafe` to this trait implementation", + "unsafe ", + rustc_errors::Applicability::MaybeIncorrect, + ) + .emit()); + } - (Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => { - return Err(struct_span_code_err!( - tcx.dcx(), - tcx.def_span(def_id), - E0569, - "requires an `unsafe impl` declaration due to `#[{}]` attribute", - attr_name - ) - .with_note(format!( - "the trait `{}` enforces invariants that the compiler can't check. \ + (Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => { + return Err(struct_span_code_err!( + tcx.dcx(), + tcx.def_span(def_id), + 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( - item.span.shrink_to_lo(), - "add `unsafe` to this trait implementation", - "unsafe ", - rustc_errors::Applicability::MaybeIncorrect, - ) - .emit()); - } + trait_ref.print_trait_sugared() + )) + .with_span_suggestion_verbose( + item.span.shrink_to_lo(), + "add `unsafe` to this trait implementation", + "unsafe ", + rustc_errors::Applicability::MaybeIncorrect, + ) + .emit()); + } - (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => { - // Reported in AST validation - tcx.dcx().span_delayed_bug(item.span, "unsafe negative impl"); - } - (_, _, Unsafety::Normal, hir::ImplPolarity::Negative(_)) - | (Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive) - | (Unsafety::Normal, Some(_), Unsafety::Unsafe, hir::ImplPolarity::Positive) - | (Unsafety::Normal, None, Unsafety::Normal, _) => { - // OK - } + (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => { + // Reported in AST validation + tcx.dcx().span_delayed_bug(item.span, "unsafe negative impl"); + Ok(()) } + (_, _, Unsafety::Normal, hir::ImplPolarity::Negative(_)) + | (Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive) + | (Unsafety::Normal, Some(_), Unsafety::Unsafe, hir::ImplPolarity::Positive) + | (Unsafety::Normal, None, Unsafety::Normal, _) => Ok(()), } - Ok(()) }