Skip to content

Commit

Permalink
do not implement unsafe auto traits for types with unsafe fields
Browse files Browse the repository at this point in the history
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 rust-lang#132922.
  • Loading branch information
jswrenn committed Dec 5, 2024
1 parent 0e98766 commit baec50e
Show file tree
Hide file tree
Showing 12 changed files with 60 additions and 0 deletions.
5 changes: 5 additions & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_middle/src/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 23 additions & 0 deletions tests/ui/unsafe-fields/auto-traits.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//@ compile-flags: --crate-type=lib

#![feature(auto_traits)]
#![feature(unsafe_fields)]
#![allow(dead_code, incomplete_features, unconditional_recursion)]

enum UnsafeEnum {
Safe(u8),
Unsafe { unsafe field: u8 },
}

auto trait SafeAuto {}

fn impl_safe_auto(_: impl SafeAuto) {
impl_safe_auto(UnsafeEnum::Safe(42))
}

unsafe auto trait UnsafeAuto {}

fn impl_unsafe_auto(_: impl UnsafeAuto) {
impl_unsafe_auto(UnsafeEnum::Safe(42))
//~^ ERROR the trait bound `UnsafeEnum: UnsafeAuto` is not satisfied
}
17 changes: 17 additions & 0 deletions tests/ui/unsafe-fields/auto-traits.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error[E0277]: the trait bound `UnsafeEnum: UnsafeAuto` is not satisfied
--> $DIR/auto-traits.rs:21: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`.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit baec50e

Please sign in to comment.