diff options
| author | León Orell Valerian Liehr <me@fmease.dev> | 2024-12-10 13:51:10 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-12-10 13:51:10 +0100 |
| commit | 3eaa785daa92be680d8549c87f1b68b811904abd (patch) | |
| tree | a31f332d55a2720c2e215d0cc3a8d158e4b2bae0 /compiler/rustc_trait_selection/src | |
| parent | ceaca6be471dffee50c5ded5fe923ec74395446a (diff) | |
| parent | 3ce35a4ec5f06828f908a018da083af5eb54301a (diff) | |
| download | rust-3eaa785daa92be680d8549c87f1b68b811904abd.tar.gz rust-3eaa785daa92be680d8549c87f1b68b811904abd.zip | |
Rollup merge of #134008 - jswrenn:unsafe-fields-copy, r=compiler-errors
Make `Copy` unsafe to implement for ADTs with `unsafe` fields As a rule, the application of `unsafe` to a declaration requires that use-sites of that declaration also entail `unsafe`. For example, a field declared `unsafe` may only be read in the lexical context of an `unsafe` block. For nearly all safe traits, the safety obligations of fields are explicitly discharged when they are mentioned in method definitions. For example, idiomatically implementing `Clone` (a safe trait) for a type with unsafe fields will require `unsafe` to clone those fields. Prior to this commit, `Copy` violated this rule. The trait is marked safe, and although it has no explicit methods, its implementation permits reads of `Self`. This commit resolves this by making `Copy` conditionally safe to implement. It remains safe to implement for ADTs without unsafe fields, but unsafe to implement for ADTs with unsafe fields. Tracking: #132922 r? ```@compiler-errors```
Diffstat (limited to 'compiler/rustc_trait_selection/src')
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/misc.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs | 2 |
2 files changed, 10 insertions, 2 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 3b17fa6b032..d216ae72913 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -18,6 +18,7 @@ pub enum CopyImplementationError<'tcx> { InfringingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>), NotAnAdt, HasDestructor, + HasUnsafeFields, } pub enum ConstParamTyImplementationError<'tcx> { @@ -39,11 +40,16 @@ pub enum InfringingFieldsReason<'tcx> { /// /// If it's not an ADT, int ty, `bool`, float ty, `char`, raw pointer, `!`, /// a reference or an array returns `Err(NotAnAdt)`. +/// +/// If the impl is `Safe`, `self_type` must not have unsafe fields. When used to +/// generate suggestions in lints, `Safe` should be supplied so as to not +/// suggest implementing `Copy` for types with unsafe fields. pub fn type_allowed_to_implement_copy<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, self_type: Ty<'tcx>, parent_cause: ObligationCause<'tcx>, + impl_safety: hir::Safety, ) -> Result<(), CopyImplementationError<'tcx>> { let (adt, args) = match self_type.kind() { // These types used to have a builtin impl. @@ -78,6 +84,10 @@ pub fn type_allowed_to_implement_copy<'tcx>( return Err(CopyImplementationError::HasDestructor); } + if impl_safety == hir::Safety::Safe && self_type.has_unsafe_fields() { + return Err(CopyImplementationError::HasUnsafeFields); + } + Ok(()) } 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 3e2c8467d32..5e27fd43789 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -795,8 +795,6 @@ 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() { |
