Store impl unsafety in impl trait header

This commit is contained in:
Oli Scherer 2024-02-11 10:43:01 +00:00
parent 09d73fab08
commit 11a73f6d4d
4 changed files with 28 additions and 24 deletions

View file

@ -132,12 +132,12 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed>
let mut res = tcx.ensure().specialization_graph_of(def_id); let mut res = tcx.ensure().specialization_graph_of(def_id);
for &impl_def_id in impls { for &impl_def_id in impls {
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity(); let trait_header = tcx.impl_trait_header(impl_def_id).unwrap().instantiate_identity();
res = res.and(check_impl(tcx, impl_def_id, trait_ref)); res = res.and(check_impl(tcx, impl_def_id, trait_header.trait_ref));
res = res.and(check_object_overlap(tcx, impl_def_id, trait_ref)); res = res.and(check_object_overlap(tcx, impl_def_id, trait_header.trait_ref));
res = res.and(unsafety::check_item(tcx, impl_def_id, trait_ref)); res = res.and(unsafety::check_item(tcx, impl_def_id, trait_header));
res = res.and(tcx.ensure().orphan_check_impl(impl_def_id)); res = res.and(tcx.ensure().orphan_check_impl(impl_def_id));
res = res.and(builtin::check_trait(tcx, def_id, impl_def_id)); res = res.and(builtin::check_trait(tcx, def_id, impl_def_id));
} }

View file

@ -2,23 +2,23 @@
//! crate or pertains to a type defined in this crate. //! crate or pertains to a type defined in this crate.
use rustc_errors::{codes::*, struct_span_code_err}; use rustc_errors::{codes::*, struct_span_code_err};
use rustc_hir as hir;
use rustc_hir::Unsafety; use rustc_hir::Unsafety;
use rustc_middle::ty::{TraitRef, TyCtxt}; use rustc_middle::ty::{ImplPolarity::*, ImplTraitHeader, TyCtxt};
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;
use rustc_span::ErrorGuaranteed; use rustc_span::ErrorGuaranteed;
pub(super) fn check_item( pub(super) fn check_item(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
def_id: LocalDefId, def_id: LocalDefId,
trait_ref: TraitRef<'_>, trait_header: ImplTraitHeader<'_>,
) -> Result<(), ErrorGuaranteed> { ) -> Result<(), ErrorGuaranteed> {
let item = tcx.hir().expect_item(def_id); let trait_ref = trait_header.trait_ref;
let impl_ = item.expect_impl();
let trait_def = tcx.trait_def(trait_ref.def_id); 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"); let unsafe_attr =
match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) { tcx.generics_of(def_id).params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
(Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => { match (trait_def.unsafety, unsafe_attr, trait_header.unsafety, trait_header.polarity) {
(Unsafety::Normal, None, Unsafety::Unsafe, Positive | Reservation) => {
let span = tcx.def_span(def_id);
return Err(struct_span_code_err!( return Err(struct_span_code_err!(
tcx.dcx(), tcx.dcx(),
tcx.def_span(def_id), tcx.def_span(def_id),
@ -27,7 +27,7 @@ pub(super) fn check_item(
trait_ref.print_trait_sugared() trait_ref.print_trait_sugared()
) )
.with_span_suggestion_verbose( .with_span_suggestion_verbose(
item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)), span.with_hi(span.lo() + rustc_span::BytePos(7)),
"remove `unsafe` from this trait implementation", "remove `unsafe` from this trait implementation",
"", "",
rustc_errors::Applicability::MachineApplicable, rustc_errors::Applicability::MachineApplicable,
@ -35,10 +35,11 @@ pub(super) fn check_item(
.emit()); .emit());
} }
(Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => { (Unsafety::Unsafe, _, Unsafety::Normal, Positive | Reservation) => {
let span = tcx.def_span(def_id);
return Err(struct_span_code_err!( return Err(struct_span_code_err!(
tcx.dcx(), tcx.dcx(),
tcx.def_span(def_id), span,
E0200, E0200,
"the trait `{}` requires an `unsafe impl` declaration", "the trait `{}` requires an `unsafe impl` declaration",
trait_ref.print_trait_sugared() trait_ref.print_trait_sugared()
@ -50,7 +51,7 @@ pub(super) fn check_item(
trait_ref.print_trait_sugared() trait_ref.print_trait_sugared()
)) ))
.with_span_suggestion_verbose( .with_span_suggestion_verbose(
item.span.shrink_to_lo(), span.shrink_to_lo(),
"add `unsafe` to this trait implementation", "add `unsafe` to this trait implementation",
"unsafe ", "unsafe ",
rustc_errors::Applicability::MaybeIncorrect, rustc_errors::Applicability::MaybeIncorrect,
@ -58,10 +59,11 @@ pub(super) fn check_item(
.emit()); .emit());
} }
(Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => { (Unsafety::Normal, Some(attr_name), Unsafety::Normal, Positive | Reservation) => {
let span = tcx.def_span(def_id);
return Err(struct_span_code_err!( return Err(struct_span_code_err!(
tcx.dcx(), tcx.dcx(),
tcx.def_span(def_id), span,
E0569, E0569,
"requires an `unsafe impl` declaration due to `#[{}]` attribute", "requires an `unsafe impl` declaration due to `#[{}]` attribute",
attr_name attr_name
@ -73,7 +75,7 @@ pub(super) fn check_item(
trait_ref.print_trait_sugared() trait_ref.print_trait_sugared()
)) ))
.with_span_suggestion_verbose( .with_span_suggestion_verbose(
item.span.shrink_to_lo(), span.shrink_to_lo(),
"add `unsafe` to this trait implementation", "add `unsafe` to this trait implementation",
"unsafe ", "unsafe ",
rustc_errors::Applicability::MaybeIncorrect, rustc_errors::Applicability::MaybeIncorrect,
@ -81,14 +83,14 @@ pub(super) fn check_item(
.emit()); .emit());
} }
(_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => { (_, _, Unsafety::Unsafe, Negative) => {
// Reported in AST validation // Reported in AST validation
tcx.dcx().span_delayed_bug(item.span, "unsafe negative impl"); tcx.dcx().span_delayed_bug(tcx.def_span(def_id), "unsafe negative impl");
Ok(()) Ok(())
} }
(_, _, Unsafety::Normal, hir::ImplPolarity::Negative(_)) (_, _, Unsafety::Normal, Negative)
| (Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive) | (Unsafety::Unsafe, _, Unsafety::Unsafe, Positive | Reservation)
| (Unsafety::Normal, Some(_), Unsafety::Unsafe, hir::ImplPolarity::Positive) | (Unsafety::Normal, Some(_), Unsafety::Unsafe, Positive | Reservation)
| (Unsafety::Normal, None, Unsafety::Normal, _) => Ok(()), | (Unsafety::Normal, None, Unsafety::Normal, _) => Ok(()),
} }
} }

View file

@ -1539,6 +1539,7 @@ fn impl_trait_header(
}; };
ty::EarlyBinder::bind(ty::ImplTraitHeader { ty::EarlyBinder::bind(ty::ImplTraitHeader {
trait_ref, trait_ref,
unsafety: impl_.unsafety,
polarity: polarity_of_impl(tcx, def_id, impl_, item.span) polarity: polarity_of_impl(tcx, def_id, impl_, item.span)
}) })
}) })

View file

@ -252,6 +252,7 @@ pub struct ImplHeader<'tcx> {
pub struct ImplTraitHeader<'tcx> { pub struct ImplTraitHeader<'tcx> {
pub trait_ref: ty::TraitRef<'tcx>, pub trait_ref: ty::TraitRef<'tcx>,
pub polarity: ImplPolarity, pub polarity: ImplPolarity,
pub unsafety: hir::Unsafety,
} }
#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)] #[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]