From e6e322f79713b156d43d77be6135463ec2d4b6e7 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Thu, 5 Dec 2024 20:15:08 +0000 Subject: [PATCH] do not implement unsafe auto traits for types with unsafe fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a type has unsafe fields, its safety invariants are not simply the conjunction of its field types' safety invariants. Consequently, it's invalid to reason about the safety properties of these types in a purely structural manner — i.e., the manner in which `auto` traits are implemented. Makes progress towards #132922. --- compiler/rustc_middle/src/ty/mod.rs | 5 +++++ compiler/rustc_middle/src/ty/util.rs | 9 +++++++++ .../src/traits/select/candidate_assembly.rs | 6 ++++++ .../auxiliary/unsafe-fields-crate-dep.rs | 0 tests/ui/{ => unsafe-fields}/unsafe-fields-crate.rs | 0 tests/ui/{ => unsafe-fields}/unsafe-fields-crate.stderr | 0 tests/ui/{ => unsafe-fields}/unsafe-fields-parse.rs | 0 tests/ui/{ => unsafe-fields}/unsafe-fields-parse.stderr | 0 tests/ui/{ => unsafe-fields}/unsafe-fields.rs | 0 tests/ui/{ => unsafe-fields}/unsafe-fields.stderr | 0 10 files changed, 20 insertions(+) rename tests/ui/{ => unsafe-fields}/auxiliary/unsafe-fields-crate-dep.rs (100%) rename tests/ui/{ => unsafe-fields}/unsafe-fields-crate.rs (100%) rename tests/ui/{ => unsafe-fields}/unsafe-fields-crate.stderr (100%) rename tests/ui/{ => unsafe-fields}/unsafe-fields-parse.rs (100%) rename tests/ui/{ => unsafe-fields}/unsafe-fields-parse.stderr (100%) rename tests/ui/{ => unsafe-fields}/unsafe-fields.rs (100%) rename tests/ui/{ => unsafe-fields}/unsafe-fields.stderr (100%) 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