about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/ty/context.rs4
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs8
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs9
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs3
-rw-r--r--compiler/rustc_type_ir/src/interner.rs3
-rw-r--r--tests/ui/unsafe-fields/auto-traits.current.stderr17
-rw-r--r--tests/ui/unsafe-fields/auto-traits.next.stderr17
-rw-r--r--tests/ui/unsafe-fields/auto-traits.rs26
-rw-r--r--tests/ui/unsafe-fields/auxiliary/unsafe-fields-crate-dep.rs (renamed from tests/ui/auxiliary/unsafe-fields-crate-dep.rs)0
-rw-r--r--tests/ui/unsafe-fields/unsafe-fields-crate.rs (renamed from tests/ui/unsafe-fields-crate.rs)0
-rw-r--r--tests/ui/unsafe-fields/unsafe-fields-crate.stderr (renamed from tests/ui/unsafe-fields-crate.stderr)0
-rw-r--r--tests/ui/unsafe-fields/unsafe-fields-parse.rs (renamed from tests/ui/unsafe-fields-parse.rs)0
-rw-r--r--tests/ui/unsafe-fields/unsafe-fields-parse.stderr (renamed from tests/ui/unsafe-fields-parse.stderr)0
-rw-r--r--tests/ui/unsafe-fields/unsafe-fields.rs (renamed from tests/ui/unsafe-fields.rs)0
-rw-r--r--tests/ui/unsafe-fields/unsafe-fields.stderr (renamed from tests/ui/unsafe-fields.stderr)0
16 files changed, 95 insertions, 0 deletions
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 3cbb2a3acf5..d4835bb07f6 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -585,6 +585,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.trait_def(trait_def_id).implement_via_object
     }
 
+    fn trait_is_unsafe(self, trait_def_id: Self::DefId) -> bool {
+        self.trait_def(trait_def_id).safety == hir::Safety::Unsafe
+    }
+
     fn is_impl_trait_in_trait(self, def_id: DefId) -> bool {
         self.is_impl_trait_in_trait(def_id)
     }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 142db8a17f0..474062218c9 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -978,6 +978,14 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
     fn async_destructor_ty(self, interner: TyCtxt<'tcx>) -> Ty<'tcx> {
         self.async_destructor_ty(interner)
     }
+
+    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
+        }
+    }
 }
 
 /// Type utilities
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 6641d2bf924..12df35d30b8 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -169,6 +169,14 @@ where
             return result;
         }
 
+        // Only consider auto impls of unsafe traits when there are no unsafe
+        // fields.
+        if ecx.cx().trait_is_unsafe(goal.predicate.def_id())
+            && goal.predicate.self_ty().has_unsafe_fields()
+        {
+            return Err(NoSolution);
+        }
+
         // We only look into opaque types during analysis for opaque types
         // outside of their defining scope. Doing so for opaques in the
         // defining scope may require calling `typeck` on the same item we're
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 32b4567aba4..3e2c8467d32 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -18,6 +18,7 @@ use rustc_infer::traits::{
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt, TypingMode};
 use rustc_middle::{bug, span_bug};
+use rustc_type_ir::Interner;
 use tracing::{debug, instrument, trace};
 
 use super::SelectionCandidate::*;
@@ -794,6 +795,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | ty::Never
                 | ty::Tuple(_)
                 | ty::CoroutineWitness(..) => {
+                    use rustc_type_ir::inherent::*;
+
+                    // 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/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index a201f2b1c11..f45c94127bd 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -136,6 +136,9 @@ pub trait Ty<I: Interner<Ty = Self>>:
         matches!(self.kind(), ty::FnPtr(..))
     }
 
+    /// Checks whether this type is an ADT that has unsafe fields.
+    fn has_unsafe_fields(self) -> bool;
+
     fn fn_sig(self, interner: I) -> ty::Binder<I, ty::FnSig<I>> {
         match self.kind() {
             ty::FnPtr(sig_tys, hdr) => sig_tys.with(hdr),
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 0ae688848eb..025ec7ae896 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -270,6 +270,9 @@ pub trait Interner:
 
     fn trait_may_be_implemented_via_object(self, trait_def_id: Self::DefId) -> bool;
 
+    /// Returns `true` if this is an `unsafe trait`.
+    fn trait_is_unsafe(self, trait_def_id: Self::DefId) -> bool;
+
     fn is_impl_trait_in_trait(self, def_id: Self::DefId) -> bool;
 
     fn delay_bug(self, msg: impl ToString) -> Self::ErrorGuaranteed;
diff --git a/tests/ui/unsafe-fields/auto-traits.current.stderr b/tests/ui/unsafe-fields/auto-traits.current.stderr
new file mode 100644
index 00000000000..53a97458b7c
--- /dev/null
+++ b/tests/ui/unsafe-fields/auto-traits.current.stderr
@@ -0,0 +1,17 @@
+error[E0277]: the trait bound `UnsafeEnum: UnsafeAuto` is not satisfied
+  --> $DIR/auto-traits.rs:24:22
+   |
+LL |     impl_unsafe_auto(UnsafeEnum::Safe(42));
+   |     ---------------- ^^^^^^^^^^^^^^^^^^^^ the trait `UnsafeAuto` is not implemented for `UnsafeEnum`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `impl_unsafe_auto`
+  --> $DIR/auto-traits.rs:20:29
+   |
+LL | fn impl_unsafe_auto(_: impl UnsafeAuto) {}
+   |                             ^^^^^^^^^^ required by this bound in `impl_unsafe_auto`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/unsafe-fields/auto-traits.next.stderr b/tests/ui/unsafe-fields/auto-traits.next.stderr
new file mode 100644
index 00000000000..53a97458b7c
--- /dev/null
+++ b/tests/ui/unsafe-fields/auto-traits.next.stderr
@@ -0,0 +1,17 @@
+error[E0277]: the trait bound `UnsafeEnum: UnsafeAuto` is not satisfied
+  --> $DIR/auto-traits.rs:24:22
+   |
+LL |     impl_unsafe_auto(UnsafeEnum::Safe(42));
+   |     ---------------- ^^^^^^^^^^^^^^^^^^^^ the trait `UnsafeAuto` is not implemented for `UnsafeEnum`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `impl_unsafe_auto`
+  --> $DIR/auto-traits.rs:20:29
+   |
+LL | fn impl_unsafe_auto(_: impl UnsafeAuto) {}
+   |                             ^^^^^^^^^^ required by this bound in `impl_unsafe_auto`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/unsafe-fields/auto-traits.rs b/tests/ui/unsafe-fields/auto-traits.rs
new file mode 100644
index 00000000000..e15d0000079
--- /dev/null
+++ b/tests/ui/unsafe-fields/auto-traits.rs
@@ -0,0 +1,26 @@
+//@ compile-flags: --crate-type=lib
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+
+#![feature(auto_traits)]
+#![feature(unsafe_fields)]
+#![allow(incomplete_features)]
+
+enum UnsafeEnum {
+    Safe(u8),
+    Unsafe { unsafe field: u8 },
+}
+
+auto trait SafeAuto {}
+
+fn impl_safe_auto(_: impl SafeAuto) {}
+
+unsafe auto trait UnsafeAuto {}
+
+fn impl_unsafe_auto(_: impl UnsafeAuto) {}
+
+fn tests() {
+    impl_safe_auto(UnsafeEnum::Safe(42));
+    impl_unsafe_auto(UnsafeEnum::Safe(42));
+    //~^ ERROR the trait bound `UnsafeEnum: UnsafeAuto` is not satisfied
+}
diff --git a/tests/ui/auxiliary/unsafe-fields-crate-dep.rs b/tests/ui/unsafe-fields/auxiliary/unsafe-fields-crate-dep.rs
index 95b928402a9..95b928402a9 100644
--- a/tests/ui/auxiliary/unsafe-fields-crate-dep.rs
+++ b/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
index cfb9ad6b544..cfb9ad6b544 100644
--- a/tests/ui/unsafe-fields-crate.rs
+++ b/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
index 778c26e0a43..778c26e0a43 100644
--- a/tests/ui/unsafe-fields-crate.stderr
+++ b/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
index 67277731293..67277731293 100644
--- a/tests/ui/unsafe-fields-parse.rs
+++ b/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
index 5a45ab03ffe..5a45ab03ffe 100644
--- a/tests/ui/unsafe-fields-parse.stderr
+++ b/tests/ui/unsafe-fields/unsafe-fields-parse.stderr
diff --git a/tests/ui/unsafe-fields.rs b/tests/ui/unsafe-fields/unsafe-fields.rs
index 637471582d7..637471582d7 100644
--- a/tests/ui/unsafe-fields.rs
+++ b/tests/ui/unsafe-fields/unsafe-fields.rs
diff --git a/tests/ui/unsafe-fields.stderr b/tests/ui/unsafe-fields/unsafe-fields.stderr
index a1c5d2b44cd..a1c5d2b44cd 100644
--- a/tests/ui/unsafe-fields.stderr
+++ b/tests/ui/unsafe-fields/unsafe-fields.stderr