diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c7a2223ecd78b..ae228a8332bca 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1837,6 +1837,11 @@ impl<'tcx> TyCtxt<'tcx> { self.trait_def(trait_def_id).has_auto_impl } + /// Returns `true` if this is an `unsafe trait`. + pub fn trait_is_unsafe(self, trait_def_id: DefId) -> bool { + self.trait_def(trait_def_id).safety == Safety::Unsafe + } + /// Returns `true` if this is coinductive, either because it is /// an auto trait or because it has the `#[rustc_coinductive]` attribute. pub fn trait_is_coinductive(self, trait_def_id: DefId) -> bool { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 57054bd1a0b24..7f28062045aa6 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1288,6 +1288,15 @@ impl<'tcx> Ty<'tcx> { } } + /// Checks whether this type directly contains unsafe fields. + pub fn has_unsafe_fields(self) -> bool { + if let ty::Adt(adt_def, ..) = self.kind() { + adt_def.all_fields().any(|x| x.safety == hir::Safety::Unsafe) + } else { + false + } + } + /// Get morphology of the async drop glue, needed for types which do not /// use async drop. To get async drop glue morphology for a definition see /// [`TyCtxt::async_drop_glue_morphology`]. Used for `AsyncDestruct::Destructor` diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 32b4567aba4f0..1d198d0277c2f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -794,6 +794,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Never | ty::Tuple(_) | ty::CoroutineWitness(..) => { + // Only consider auto impls of unsafe traits when there are + // no unsafe fields. + if self.tcx().trait_is_unsafe(def_id) && self_ty.has_unsafe_fields() { + return; + } + // Only consider auto impls if there are no manual impls for the root of `self_ty`. // // For example, we only consider auto candidates for `&i32: Auto` if no explicit impl diff --git a/tests/ui/auxiliary/unsafe-fields-crate-dep.rs b/tests/ui/unsafe-fields/auxiliary/unsafe-fields-crate-dep.rs similarity index 100% rename from tests/ui/auxiliary/unsafe-fields-crate-dep.rs rename to tests/ui/unsafe-fields/auxiliary/unsafe-fields-crate-dep.rs diff --git a/tests/ui/unsafe-fields-crate.rs b/tests/ui/unsafe-fields/unsafe-fields-crate.rs similarity index 100% rename from tests/ui/unsafe-fields-crate.rs rename to tests/ui/unsafe-fields/unsafe-fields-crate.rs diff --git a/tests/ui/unsafe-fields-crate.stderr b/tests/ui/unsafe-fields/unsafe-fields-crate.stderr similarity index 100% rename from tests/ui/unsafe-fields-crate.stderr rename to tests/ui/unsafe-fields/unsafe-fields-crate.stderr diff --git a/tests/ui/unsafe-fields-parse.rs b/tests/ui/unsafe-fields/unsafe-fields-parse.rs similarity index 100% rename from tests/ui/unsafe-fields-parse.rs rename to tests/ui/unsafe-fields/unsafe-fields-parse.rs diff --git a/tests/ui/unsafe-fields-parse.stderr b/tests/ui/unsafe-fields/unsafe-fields-parse.stderr similarity index 100% rename from tests/ui/unsafe-fields-parse.stderr rename to tests/ui/unsafe-fields/unsafe-fields-parse.stderr diff --git a/tests/ui/unsafe-fields.rs b/tests/ui/unsafe-fields/unsafe-fields.rs similarity index 100% rename from tests/ui/unsafe-fields.rs rename to tests/ui/unsafe-fields/unsafe-fields.rs diff --git a/tests/ui/unsafe-fields.stderr b/tests/ui/unsafe-fields/unsafe-fields.stderr similarity index 100% rename from tests/ui/unsafe-fields.stderr rename to tests/ui/unsafe-fields/unsafe-fields.stderr