summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_typeck/src/coherence
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs (renamed from compiler/rustc_typeck/src/coherence/inherent_impls.rs)18
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs (renamed from compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs)58
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/mod.rs (renamed from compiler/rustc_typeck/src/coherence/mod.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs (renamed from compiler/rustc_typeck/src/coherence/orphan.rs)38
-rw-r--r--compiler/rustc_typeck/src/coherence/builtin.rs603
-rw-r--r--compiler/rustc_typeck/src/coherence/unsafety.rs66
6 files changed, 70 insertions, 713 deletions
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 52aad636f..2890c149b 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -58,7 +58,7 @@ const ADD_ATTR: &str =
impl<'tcx> InherentCollect<'tcx> {
fn check_def_id(&mut self, item: &hir::Item<'_>, self_ty: Ty<'tcx>, def_id: DefId) {
- let impl_def_id = item.def_id;
+ let impl_def_id = item.owner_id;
if let Some(def_id) = def_id.as_local() {
// Add the implementation to the mapping from implementation to base
// type def ID, if there is a base type for this implementation and
@@ -89,7 +89,7 @@ impl<'tcx> InherentCollect<'tcx> {
for impl_item in items {
if !self
.tcx
- .has_attr(impl_item.id.def_id.to_def_id(), sym::rustc_allow_incoherent_impl)
+ .has_attr(impl_item.id.owner_id.to_def_id(), sym::rustc_allow_incoherent_impl)
{
struct_span_err!(
self.tcx.sess,
@@ -105,7 +105,7 @@ impl<'tcx> InherentCollect<'tcx> {
}
if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsInfer) {
- self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
+ self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id.def_id);
} else {
bug!("unexpected self type: {:?}", self_ty);
}
@@ -135,7 +135,7 @@ impl<'tcx> InherentCollect<'tcx> {
for item in items {
if !self
.tcx
- .has_attr(item.id.def_id.to_def_id(), sym::rustc_allow_incoherent_impl)
+ .has_attr(item.id.owner_id.to_def_id(), sym::rustc_allow_incoherent_impl)
{
struct_span_err!(
self.tcx.sess,
@@ -177,7 +177,7 @@ impl<'tcx> InherentCollect<'tcx> {
}
fn check_item(&mut self, id: hir::ItemId) {
- if !matches!(self.tcx.def_kind(id.def_id), DefKind::Impl) {
+ if !matches!(self.tcx.def_kind(id.owner_id), DefKind::Impl) {
return;
}
@@ -186,7 +186,7 @@ impl<'tcx> InherentCollect<'tcx> {
return;
};
- let self_ty = self.tcx.type_of(item.def_id);
+ let self_ty = self.tcx.type_of(item.owner_id);
match *self_ty.kind() {
ty::Adt(def, _) => {
self.check_def_id(item, self_ty, def.did());
@@ -220,7 +220,9 @@ impl<'tcx> InherentCollect<'tcx> {
| ty::Ref(..)
| ty::Never
| ty::FnPtr(_)
- | ty::Tuple(..) => self.check_primitive_impl(item.def_id, self_ty, items, ty.span),
+ | ty::Tuple(..) => {
+ self.check_primitive_impl(item.owner_id.def_id, self_ty, items, ty.span)
+ }
ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => {
let mut err = struct_span_err!(
self.tcx.sess,
@@ -241,7 +243,7 @@ impl<'tcx> InherentCollect<'tcx> {
| ty::Bound(..)
| ty::Placeholder(_)
| ty::Infer(_) => {
- bug!("unexpected impl self type of impl: {:?} {:?}", item.def_id, self_ty);
+ bug!("unexpected impl self type of impl: {:?} {:?}", item.owner_id, self_ty);
}
ty::Error(_) => {}
}
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
index 03e076bf5..972769eb1 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
@@ -58,6 +58,37 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
== item2.ident(self.tcx).normalize_to_macros_2_0()
}
+ fn check_for_duplicate_items_in_impl(&self, impl_: DefId) {
+ let impl_items = self.tcx.associated_items(impl_);
+
+ let mut seen_items = FxHashMap::default();
+ for impl_item in impl_items.in_definition_order() {
+ let span = self.tcx.def_span(impl_item.def_id);
+ let ident = impl_item.ident(self.tcx);
+
+ let norm_ident = ident.normalize_to_macros_2_0();
+ match seen_items.entry(norm_ident) {
+ Entry::Occupied(entry) => {
+ let former = entry.get();
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0592,
+ "duplicate definitions with name `{}`",
+ ident,
+ );
+ err.span_label(span, format!("duplicate definitions for `{}`", ident));
+ err.span_label(*former, format!("other definition for `{}`", ident));
+
+ err.emit();
+ }
+ Entry::Vacant(entry) => {
+ entry.insert(span);
+ }
+ }
+ }
+ }
+
fn check_for_common_items_in_impls(
&self,
impl1: DefId,
@@ -117,29 +148,22 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
// inherent impls without warning.
SkipLeakCheck::Yes,
overlap_mode,
- |overlap| {
- self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap);
- false
- },
- || true,
- );
+ )
+ .map_or(true, |overlap| {
+ self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap);
+ false
+ });
}
fn check_item(&mut self, id: hir::ItemId) {
- let def_kind = self.tcx.def_kind(id.def_id);
+ let def_kind = self.tcx.def_kind(id.owner_id);
if !matches!(def_kind, DefKind::Enum | DefKind::Struct | DefKind::Trait | DefKind::Union) {
return;
}
- let impls = self.tcx.inherent_impls(id.def_id);
+ let impls = self.tcx.inherent_impls(id.owner_id);
- // If there is only one inherent impl block,
- // there is nothing to overlap check it with
- if impls.len() <= 1 {
- return;
- }
-
- let overlap_mode = OverlapMode::get(self.tcx, id.def_id.to_def_id());
+ let overlap_mode = OverlapMode::get(self.tcx, id.owner_id.to_def_id());
let impls_items = impls
.iter()
@@ -152,6 +176,8 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
const ALLOCATING_ALGO_THRESHOLD: usize = 500;
if impls.len() < ALLOCATING_ALGO_THRESHOLD {
for (i, &(&impl1_def_id, impl_items1)) in impls_items.iter().enumerate() {
+ self.check_for_duplicate_items_in_impl(impl1_def_id);
+
for &(&impl2_def_id, impl_items2) in &impls_items[(i + 1)..] {
if self.impls_have_common_items(impl_items1, impl_items2) {
self.check_for_overlapping_inherent_impls(
@@ -290,6 +316,8 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
impl_blocks.sort_unstable();
for (i, &impl1_items_idx) in impl_blocks.iter().enumerate() {
let &(&impl1_def_id, impl_items1) = &impls_items[impl1_items_idx];
+ self.check_for_duplicate_items_in_impl(impl1_def_id);
+
for &impl2_items_idx in impl_blocks[(i + 1)..].iter() {
let &(&impl2_def_id, impl_items2) = &impls_items[impl2_items_idx];
if self.impls_have_common_items(impl_items1, impl_items2) {
diff --git a/compiler/rustc_typeck/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index ae9ebe590..ae9ebe590 100644
--- a/compiler/rustc_typeck/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 1608550aa..bb45c3823 100644
--- a/compiler/rustc_typeck/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -2,10 +2,9 @@
//! crate or pertains to a type defined in this crate.
use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, DelayDm};
use rustc_errors::{Diagnostic, ErrorGuaranteed};
use rustc_hir as hir;
-use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::util::IgnoreRegions;
@@ -43,7 +42,7 @@ fn do_orphan_check_impl<'tcx>(
) -> Result<(), ErrorGuaranteed> {
let trait_def_id = trait_ref.def_id;
- let item = tcx.hir().item(hir::ItemId { def_id });
+ let item = tcx.hir().expect_item(def_id);
let hir::ItemKind::Impl(ref impl_) = item.kind else {
bug!("{:?} is not an impl: {:?}", def_id, item);
};
@@ -102,7 +101,7 @@ fn do_orphan_check_impl<'tcx>(
span_bug!(sp, "opaque type not found, but `has_opaque_types` is set")
}
- match traits::orphan_check(tcx, item.def_id.to_def_id()) {
+ match traits::orphan_check(tcx, item.owner_id.to_def_id()) {
Ok(()) => {}
Err(err) => emit_orphan_check_error(
tcx,
@@ -229,12 +228,8 @@ fn emit_orphan_check_error<'tcx>(
"only traits defined in the current crate {msg}"
);
err.span_label(sp, "impl doesn't use only types from inside the current crate");
- for (ty, is_target_ty) in &tys {
- let mut ty = *ty;
- tcx.infer_ctxt().enter(|infcx| {
- // Remove the lifetimes unnecessary for this error.
- ty = infcx.freshen(ty);
- });
+ for &(mut ty, is_target_ty) in &tys {
+ ty = tcx.erase_regions(ty);
ty = match ty.kind() {
// Remove the type arguments from the output, as they are not relevant.
// You can think of this as the reverse of `resolve_vars_if_possible`.
@@ -264,7 +259,7 @@ fn emit_orphan_check_error<'tcx>(
};
let msg = format!("{} is not defined in the current crate{}", ty, postfix);
- if *is_target_ty {
+ if is_target_ty {
// Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
err.span_label(self_ty_span, &msg);
} else {
@@ -417,30 +412,31 @@ fn lint_auto_trait_impl<'tcx>(
lint::builtin::SUSPICIOUS_AUTO_TRAIT_IMPLS,
tcx.hir().local_def_id_to_hir_id(impl_def_id),
tcx.def_span(impl_def_id),
- |err| {
- let item_span = tcx.def_span(self_type_did);
- let self_descr = tcx.def_kind(self_type_did).descr(self_type_did);
- let mut err = err.build(&format!(
+ DelayDm(|| {
+ format!(
"cross-crate traits with a default impl, like `{}`, \
should not be specialized",
tcx.def_path_str(trait_ref.def_id),
- ));
+ )
+ }),
+ |lint| {
+ let item_span = tcx.def_span(self_type_did);
+ let self_descr = tcx.def_kind(self_type_did).descr(self_type_did);
match arg {
ty::util::NotUniqueParam::DuplicateParam(arg) => {
- err.note(&format!("`{}` is mentioned multiple times", arg));
+ lint.note(&format!("`{}` is mentioned multiple times", arg));
}
ty::util::NotUniqueParam::NotParam(arg) => {
- err.note(&format!("`{}` is not a generic parameter", arg));
+ lint.note(&format!("`{}` is not a generic parameter", arg));
}
}
- err.span_note(
+ lint.span_note(
item_span,
&format!(
"try using the same sequence of generic parameters as the {} definition",
self_descr,
),
- );
- err.emit();
+ )
},
);
}
diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs
deleted file mode 100644
index 50946cc1d..000000000
--- a/compiler/rustc_typeck/src/coherence/builtin.rs
+++ /dev/null
@@ -1,603 +0,0 @@
-//! Check properties that are required by built-in traits and set
-//! up data structures required by type-checking/codegen.
-
-use crate::errors::{CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem};
-use rustc_errors::{struct_span_err, MultiSpan};
-use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::lang_items::LangItem;
-use rustc_hir::ItemKind;
-use rustc_infer::infer;
-use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::TyCtxtInferExt;
-use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
-use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitable};
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
-use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
-use rustc_trait_selection::traits::predicate_for_trait_def;
-use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt};
-use std::collections::BTreeMap;
-
-pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
- let lang_items = tcx.lang_items();
- Checker { tcx, trait_def_id }
- .check(lang_items.drop_trait(), visit_implementation_of_drop)
- .check(lang_items.copy_trait(), visit_implementation_of_copy)
- .check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)
- .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn);
-}
-
-struct Checker<'tcx> {
- tcx: TyCtxt<'tcx>,
- trait_def_id: DefId,
-}
-
-impl<'tcx> Checker<'tcx> {
- fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> &Self
- where
- F: FnMut(TyCtxt<'tcx>, LocalDefId),
- {
- if Some(self.trait_def_id) == trait_def_id {
- for &impl_def_id in self.tcx.hir().trait_impls(self.trait_def_id) {
- f(self.tcx, impl_def_id);
- }
- }
- self
- }
-}
-
-fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
- // Destructors only work on nominal types.
- if let ty::Adt(..) | ty::Error(_) = tcx.type_of(impl_did).kind() {
- return;
- }
-
- let sp = match tcx.hir().expect_item(impl_did).kind {
- ItemKind::Impl(ref impl_) => impl_.self_ty.span,
- _ => bug!("expected Drop impl item"),
- };
-
- tcx.sess.emit_err(DropImplOnWrongItem { span: sp });
-}
-
-fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
- debug!("visit_implementation_of_copy: impl_did={:?}", impl_did);
-
- let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
-
- let self_type = tcx.type_of(impl_did);
- debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type);
-
- let span = tcx.hir().span(impl_hir_id);
- let param_env = tcx.param_env(impl_did);
- assert!(!self_type.has_escaping_bound_vars());
-
- debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
-
- let cause = traits::ObligationCause::misc(span, impl_hir_id);
- match can_type_implement_copy(tcx, param_env, self_type, cause) {
- Ok(()) => {}
- Err(CopyImplementationError::InfrigingFields(fields)) => {
- let item = tcx.hir().expect_item(impl_did);
- let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(ref tr), .. }) = item.kind {
- tr.path.span
- } else {
- span
- };
-
- let mut err = struct_span_err!(
- tcx.sess,
- span,
- E0204,
- "the trait `Copy` may not be implemented for this type"
- );
-
- // We'll try to suggest constraining type parameters to fulfill the requirements of
- // their `Copy` implementation.
- let mut errors: BTreeMap<_, Vec<_>> = Default::default();
- let mut bounds = vec![];
-
- for (field, ty) in fields {
- let field_span = tcx.def_span(field.did);
- let field_ty_span = match tcx.hir().get_if_local(field.did) {
- Some(hir::Node::Field(field_def)) => field_def.ty.span,
- _ => field_span,
- };
- err.span_label(field_span, "this field does not implement `Copy`");
- // Spin up a new FulfillmentContext, so we can get the _precise_ reason
- // why this field does not implement Copy. This is useful because sometimes
- // it is not immediately clear why Copy is not implemented for a field, since
- // all we point at is the field itself.
- tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
- fulfill_cx.register_bound(
- &infcx,
- param_env,
- ty,
- tcx.lang_items().copy_trait().unwrap(),
- traits::ObligationCause::dummy_with_span(field_ty_span),
- );
- for error in fulfill_cx.select_all_or_error(&infcx) {
- let error_predicate = error.obligation.predicate;
- // Only note if it's not the root obligation, otherwise it's trivial and
- // should be self-explanatory (i.e. a field literally doesn't implement Copy).
-
- // FIXME: This error could be more descriptive, especially if the error_predicate
- // contains a foreign type or if it's a deeply nested type...
- if error_predicate != error.root_obligation.predicate {
- errors
- .entry((ty.to_string(), error_predicate.to_string()))
- .or_default()
- .push(error.obligation.cause.span);
- }
- if let ty::PredicateKind::Trait(ty::TraitPredicate {
- trait_ref,
- polarity: ty::ImplPolarity::Positive,
- ..
- }) = error_predicate.kind().skip_binder()
- {
- let ty = trait_ref.self_ty();
- if let ty::Param(_) = ty.kind() {
- bounds.push((
- format!("{ty}"),
- trait_ref.print_only_trait_path().to_string(),
- Some(trait_ref.def_id),
- ));
- }
- }
- }
- });
- }
- for ((ty, error_predicate), spans) in errors {
- let span: MultiSpan = spans.into();
- err.span_note(
- span,
- &format!("the `Copy` impl for `{}` requires that `{}`", ty, error_predicate),
- );
- }
- suggest_constraining_type_params(
- tcx,
- tcx.hir().get_generics(impl_did).expect("impls always have generics"),
- &mut err,
- bounds.iter().map(|(param, constraint, def_id)| {
- (param.as_str(), constraint.as_str(), *def_id)
- }),
- );
- err.emit();
- }
- Err(CopyImplementationError::NotAnAdt) => {
- let item = tcx.hir().expect_item(impl_did);
- let span =
- if let ItemKind::Impl(ref impl_) = item.kind { impl_.self_ty.span } else { span };
-
- tcx.sess.emit_err(CopyImplOnNonAdt { span });
- }
- Err(CopyImplementationError::HasDestructor) => {
- tcx.sess.emit_err(CopyImplOnTypeWithDtor { span });
- }
- }
-}
-
-fn visit_implementation_of_coerce_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) {
- debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
-
- // Just compute this for the side-effects, in particular reporting
- // errors; other parts of the code may demand it for the info of
- // course.
- let span = tcx.def_span(impl_did);
- tcx.at(span).coerce_unsized_info(impl_did);
-}
-
-fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) {
- debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
-
- let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
- let span = tcx.hir().span(impl_hir_id);
-
- let dispatch_from_dyn_trait = tcx.require_lang_item(LangItem::DispatchFromDyn, Some(span));
-
- let source = tcx.type_of(impl_did);
- assert!(!source.has_escaping_bound_vars());
- let target = {
- let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
- assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait);
-
- trait_ref.substs.type_at(1)
- };
-
- debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source, target);
-
- let param_env = tcx.param_env(impl_did);
-
- let create_err = |msg: &str| struct_span_err!(tcx.sess, span, E0378, "{}", msg);
-
- tcx.infer_ctxt().enter(|infcx| {
- let cause = ObligationCause::misc(span, impl_hir_id);
-
- use rustc_type_ir::sty::TyKind::*;
- match (source.kind(), target.kind()) {
- (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
- if infcx.at(&cause, param_env).eq(r_a, *r_b).is_ok() && mutbl_a == *mutbl_b => {}
- (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (),
- (&Adt(def_a, substs_a), &Adt(def_b, substs_b))
- if def_a.is_struct() && def_b.is_struct() =>
- {
- if def_a != def_b {
- let source_path = tcx.def_path_str(def_a.did());
- let target_path = tcx.def_path_str(def_b.did());
-
- create_err(&format!(
- "the trait `DispatchFromDyn` may only be implemented \
- for a coercion between structures with the same \
- definition; expected `{}`, found `{}`",
- source_path, target_path,
- ))
- .emit();
-
- return;
- }
-
- if def_a.repr().c() || def_a.repr().packed() {
- create_err(
- "structs implementing `DispatchFromDyn` may not have \
- `#[repr(packed)]` or `#[repr(C)]`",
- )
- .emit();
- }
-
- let fields = &def_a.non_enum_variant().fields;
-
- let coerced_fields = fields
- .iter()
- .filter(|field| {
- let ty_a = field.ty(tcx, substs_a);
- let ty_b = field.ty(tcx, substs_b);
-
- if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) {
- if layout.is_zst() && layout.align.abi.bytes() == 1 {
- // ignore ZST fields with alignment of 1 byte
- return false;
- }
- }
-
- if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) {
- if ok.obligations.is_empty() {
- create_err(
- "the trait `DispatchFromDyn` may only be implemented \
- for structs containing the field being coerced, \
- ZST fields with 1 byte alignment, and nothing else",
- )
- .note(&format!(
- "extra field `{}` of type `{}` is not allowed",
- field.name, ty_a,
- ))
- .emit();
-
- return false;
- }
- }
-
- return true;
- })
- .collect::<Vec<_>>();
-
- if coerced_fields.is_empty() {
- create_err(
- "the trait `DispatchFromDyn` may only be implemented \
- for a coercion between structures with a single field \
- being coerced, none found",
- )
- .emit();
- } else if coerced_fields.len() > 1 {
- create_err(
- "implementing the `DispatchFromDyn` trait requires multiple coercions",
- )
- .note(
- "the trait `DispatchFromDyn` may only be implemented \
- for a coercion between structures with a single field \
- being coerced",
- )
- .note(&format!(
- "currently, {} fields need coercions: {}",
- coerced_fields.len(),
- coerced_fields
- .iter()
- .map(|field| {
- format!(
- "`{}` (`{}` to `{}`)",
- field.name,
- field.ty(tcx, substs_a),
- field.ty(tcx, substs_b),
- )
- })
- .collect::<Vec<_>>()
- .join(", ")
- ))
- .emit();
- } else {
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-
- for field in coerced_fields {
- let predicate = predicate_for_trait_def(
- tcx,
- param_env,
- cause.clone(),
- dispatch_from_dyn_trait,
- 0,
- field.ty(tcx, substs_a),
- &[field.ty(tcx, substs_b).into()],
- );
-
- fulfill_cx.register_predicate_obligation(&infcx, predicate);
- }
-
- // Check that all transitive obligations are satisfied.
- let errors = fulfill_cx.select_all_or_error(&infcx);
- if !errors.is_empty() {
- infcx.report_fulfillment_errors(&errors, None, false);
- }
-
- // Finally, resolve all regions.
- let outlives_env = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
- }
- }
- _ => {
- create_err(
- "the trait `DispatchFromDyn` may only be implemented \
- for a coercion between structures",
- )
- .emit();
- }
- }
- })
-}
-
-pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo {
- debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
-
- // this provider should only get invoked for local def-ids
- let impl_did = impl_did.expect_local();
- let span = tcx.def_span(impl_did);
-
- let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span));
-
- let unsize_trait = tcx.lang_items().require(LangItem::Unsize).unwrap_or_else(|err| {
- tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
- });
-
- let source = tcx.type_of(impl_did);
- let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
- assert_eq!(trait_ref.def_id, coerce_unsized_trait);
- let target = trait_ref.substs.type_at(1);
- debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
-
- let param_env = tcx.param_env(impl_did);
- assert!(!source.has_escaping_bound_vars());
-
- let err_info = CoerceUnsizedInfo { custom_kind: None };
-
- debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
-
- tcx.infer_ctxt().enter(|infcx| {
- let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
- let cause = ObligationCause::misc(span, impl_hir_id);
- let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
- mt_b: ty::TypeAndMut<'tcx>,
- mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
- if (mt_a.mutbl, mt_b.mutbl) == (hir::Mutability::Not, hir::Mutability::Mut) {
- infcx
- .report_mismatched_types(
- &cause,
- mk_ptr(mt_b.ty),
- target,
- ty::error::TypeError::Mutability,
- )
- .emit();
- }
- (mt_a.ty, mt_b.ty, unsize_trait, None)
- };
- let (source, target, trait_def_id, kind) = match (source.kind(), target.kind()) {
- (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
- infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
- let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
- let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
- check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
- }
-
- (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(mt_b)) => {
- let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
- check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
- }
-
- (&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => {
- check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
- }
-
- (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b))
- if def_a.is_struct() && def_b.is_struct() =>
- {
- if def_a != def_b {
- let source_path = tcx.def_path_str(def_a.did());
- let target_path = tcx.def_path_str(def_b.did());
- struct_span_err!(
- tcx.sess,
- span,
- E0377,
- "the trait `CoerceUnsized` may only be implemented \
- for a coercion between structures with the same \
- definition; expected `{}`, found `{}`",
- source_path,
- target_path
- )
- .emit();
- return err_info;
- }
-
- // Here we are considering a case of converting
- // `S<P0...Pn>` to S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`,
- // which acts like a pointer to `U`, but carries along some extra data of type `T`:
- //
- // struct Foo<T, U> {
- // extra: T,
- // ptr: *mut U,
- // }
- //
- // We might have an impl that allows (e.g.) `Foo<T, [i32; 3]>` to be unsized
- // to `Foo<T, [i32]>`. That impl would look like:
- //
- // impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {}
- //
- // Here `U = [i32; 3]` and `V = [i32]`. At runtime,
- // when this coercion occurs, we would be changing the
- // field `ptr` from a thin pointer of type `*mut [i32;
- // 3]` to a fat pointer of type `*mut [i32]` (with
- // extra data `3`). **The purpose of this check is to
- // make sure that we know how to do this conversion.**
- //
- // To check if this impl is legal, we would walk down
- // the fields of `Foo` and consider their types with
- // both substitutes. We are looking to find that
- // exactly one (non-phantom) field has changed its
- // type, which we will expect to be the pointer that
- // is becoming fat (we could probably generalize this
- // to multiple thin pointers of the same type becoming
- // fat, but we don't). In this case:
- //
- // - `extra` has type `T` before and type `T` after
- // - `ptr` has type `*mut U` before and type `*mut V` after
- //
- // Since just one field changed, we would then check
- // that `*mut U: CoerceUnsized<*mut V>` is implemented
- // (in other words, that we know how to do this
- // conversion). This will work out because `U:
- // Unsize<V>`, and we have a builtin rule that `*mut
- // U` can be coerced to `*mut V` if `U: Unsize<V>`.
- let fields = &def_a.non_enum_variant().fields;
- let diff_fields = fields
- .iter()
- .enumerate()
- .filter_map(|(i, f)| {
- let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
-
- if tcx.type_of(f.did).is_phantom_data() {
- // Ignore PhantomData fields
- return None;
- }
-
- // Ignore fields that aren't changed; it may
- // be that we could get away with subtyping or
- // something more accepting, but we use
- // equality because we want to be able to
- // perform this check without computing
- // variance where possible. (This is because
- // we may have to evaluate constraint
- // expressions in the course of execution.)
- // See e.g., #41936.
- if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) {
- if ok.obligations.is_empty() {
- return None;
- }
- }
-
- // Collect up all fields that were significantly changed
- // i.e., those that contain T in coerce_unsized T -> U
- Some((i, a, b))
- })
- .collect::<Vec<_>>();
-
- if diff_fields.is_empty() {
- struct_span_err!(
- tcx.sess,
- span,
- E0374,
- "the trait `CoerceUnsized` may only be implemented \
- for a coercion between structures with one field \
- being coerced, none found"
- )
- .emit();
- return err_info;
- } else if diff_fields.len() > 1 {
- let item = tcx.hir().expect_item(impl_did);
- let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) =
- item.kind
- {
- t.path.span
- } else {
- tcx.def_span(impl_did)
- };
-
- struct_span_err!(
- tcx.sess,
- span,
- E0375,
- "implementing the trait \
- `CoerceUnsized` requires multiple \
- coercions"
- )
- .note(
- "`CoerceUnsized` may only be implemented for \
- a coercion between structures with one field being coerced",
- )
- .note(&format!(
- "currently, {} fields need coercions: {}",
- diff_fields.len(),
- diff_fields
- .iter()
- .map(|&(i, a, b)| {
- format!("`{}` (`{}` to `{}`)", fields[i].name, a, b)
- })
- .collect::<Vec<_>>()
- .join(", ")
- ))
- .span_label(span, "requires multiple coercions")
- .emit();
- return err_info;
- }
-
- let (i, a, b) = diff_fields[0];
- let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
- (a, b, coerce_unsized_trait, Some(kind))
- }
-
- _ => {
- struct_span_err!(
- tcx.sess,
- span,
- E0376,
- "the trait `CoerceUnsized` may only be implemented \
- for a coercion between structures"
- )
- .emit();
- return err_info;
- }
- };
-
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-
- // Register an obligation for `A: Trait<B>`.
- let cause = traits::ObligationCause::misc(span, impl_hir_id);
- let predicate = predicate_for_trait_def(
- tcx,
- param_env,
- cause,
- trait_def_id,
- 0,
- source,
- &[target.into()],
- );
- fulfill_cx.register_predicate_obligation(&infcx, predicate);
-
- // Check that all transitive obligations are satisfied.
- let errors = fulfill_cx.select_all_or_error(&infcx);
- if !errors.is_empty() {
- infcx.report_fulfillment_errors(&errors, None, false);
- }
-
- // Finally, resolve all regions.
- let outlives_env = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
-
- CoerceUnsizedInfo { custom_kind: kind }
- })
-}
diff --git a/compiler/rustc_typeck/src/coherence/unsafety.rs b/compiler/rustc_typeck/src/coherence/unsafety.rs
deleted file mode 100644
index e45fb5fe4..000000000
--- a/compiler/rustc_typeck/src/coherence/unsafety.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-//! Unsafety checker: every impl either implements a trait defined in this
-//! crate or pertains to a type defined in this crate.
-
-use rustc_errors::struct_span_err;
-use rustc_hir as hir;
-use rustc_hir::def::DefKind;
-use rustc_hir::Unsafety;
-use rustc_middle::ty::TyCtxt;
-use rustc_span::def_id::LocalDefId;
-
-pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
- debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Impl));
- let item = tcx.hir().expect_item(def_id);
- let hir::ItemKind::Impl(ref impl_) = item.kind else { bug!() };
-
- if let Some(trait_ref) = tcx.impl_trait_ref(item.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");
- match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) {
- (Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
- struct_span_err!(
- tcx.sess,
- item.span,
- E0199,
- "implementing the trait `{}` is not unsafe",
- trait_ref.print_only_trait_path()
- )
- .emit();
- }
-
- (Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
- struct_span_err!(
- tcx.sess,
- item.span,
- E0200,
- "the trait `{}` requires an `unsafe impl` declaration",
- trait_ref.print_only_trait_path()
- )
- .emit();
- }
-
- (Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => {
- struct_span_err!(
- tcx.sess,
- item.span,
- E0569,
- "requires an `unsafe impl` declaration due to `#[{}]` attribute",
- attr_name
- )
- .emit();
- }
-
- (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => {
- // Reported in AST validation
- tcx.sess.delay_span_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
- }
- }
- }
-}