diff options
| author | Matthias Krüger <476013+matthiaskrgr@users.noreply.github.com> | 2025-04-15 21:16:03 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-04-15 21:16:03 +0200 |
| commit | 27f1f4d27bae567c011f50bc7dacb8b65b90ad8d (patch) | |
| tree | b0a61d88980bce9caf9d4d26905157222849fd92 /compiler/rustc_monomorphize | |
| parent | ca0b7f4dcf2cbac004644831c70b0d7e3f645eeb (diff) | |
| parent | 3df7882272c96a19bcff6269e4f9f0aba34b6c6f (diff) | |
| download | rust-27f1f4d27bae567c011f50bc7dacb8b65b90ad8d.tar.gz rust-27f1f4d27bae567c011f50bc7dacb8b65b90ad8d.zip | |
Rollup merge of #139818 - compiler-errors:normalize-tails, r=oli-obk
Normalize ADT field in `find_tails_for_unsizing` See the comment inline and in the test. TL;DR is that we're getting getting a type from a `type_of` query and then matching on it structurally in codegen, so we're obligated to normalize it. The fact that this wasn't triggered earlier is that all of the types that have `CoerceUnsized` implementations never encounter aliases when peeling the ADT down to their base reference/ptr type. **NOTE**: I also renamed some things and reorganized the function a bit. Fixes #139812 Fixes #74451, which I didn't think was interesting enough to add another test. r? oli-obk
Diffstat (limited to 'compiler/rustc_monomorphize')
| -rw-r--r-- | compiler/rustc_monomorphize/src/collector.rs | 63 |
1 files changed, 32 insertions, 31 deletions
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 1dbb35f92c2..d1d0f7cacae 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -688,7 +688,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { let target_ty = self.monomorphize(target_ty); let source_ty = self.monomorphize(source_ty); let (source_ty, target_ty) = - find_vtable_types_for_unsizing(self.tcx.at(span), source_ty, target_ty); + find_tails_for_unsizing(self.tcx.at(span), source_ty, target_ty); // This could also be a different Unsize instruction, like // from a fixed sized array to a slice. But we are only // interested in things that produce a vtable. @@ -1037,36 +1037,35 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> /// /// Finally, there is also the case of custom unsizing coercions, e.g., for /// smart pointers such as `Rc` and `Arc`. -fn find_vtable_types_for_unsizing<'tcx>( +fn find_tails_for_unsizing<'tcx>( tcx: TyCtxtAt<'tcx>, source_ty: Ty<'tcx>, target_ty: Ty<'tcx>, ) -> (Ty<'tcx>, Ty<'tcx>) { - let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| { - let typing_env = ty::TypingEnv::fully_monomorphized(); - if tcx.type_has_metadata(inner_source, typing_env) { - (inner_source, inner_target) - } else { - tcx.struct_lockstep_tails_for_codegen(inner_source, inner_target, typing_env) - } - }; + let typing_env = ty::TypingEnv::fully_monomorphized(); + debug_assert!(!source_ty.has_param(), "{source_ty} should be fully monomorphic"); + debug_assert!(!target_ty.has_param(), "{target_ty} should be fully monomorphic"); match (source_ty.kind(), target_ty.kind()) { - (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _)) - | (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => ptr_vtable(a, b), + ( + &ty::Ref(_, source_pointee, _), + &ty::Ref(_, target_pointee, _) | &ty::RawPtr(target_pointee, _), + ) + | (&ty::RawPtr(source_pointee, _), &ty::RawPtr(target_pointee, _)) => { + tcx.struct_lockstep_tails_for_codegen(source_pointee, target_pointee, typing_env) + } + + // `Box<T>` could go through the ADT code below, b/c it'll unpeel to `Unique<T>`, + // and eventually bottom out in a raw ref, but we can micro-optimize it here. (_, _) if let Some(source_boxed) = source_ty.boxed_ty() && let Some(target_boxed) = target_ty.boxed_ty() => { - ptr_vtable(source_boxed, target_boxed) + tcx.struct_lockstep_tails_for_codegen(source_boxed, target_boxed, typing_env) } - // T as dyn* Trait - (_, &ty::Dynamic(_, _, ty::DynStar)) => ptr_vtable(source_ty, target_ty), - (&ty::Adt(source_adt_def, source_args), &ty::Adt(target_adt_def, target_args)) => { assert_eq!(source_adt_def, target_adt_def); - let CustomCoerceUnsized::Struct(coerce_index) = match crate::custom_coerce_unsize_info(tcx, source_ty, target_ty) { Ok(ccu) => ccu, @@ -1075,21 +1074,23 @@ fn find_vtable_types_for_unsizing<'tcx>( return (e, e); } }; + let coerce_field = &source_adt_def.non_enum_variant().fields[coerce_index]; + // We're getting a possibly unnormalized type, so normalize it. + let source_field = + tcx.normalize_erasing_regions(typing_env, coerce_field.ty(*tcx, source_args)); + let target_field = + tcx.normalize_erasing_regions(typing_env, coerce_field.ty(*tcx, target_args)); + find_tails_for_unsizing(tcx, source_field, target_field) + } - let source_fields = &source_adt_def.non_enum_variant().fields; - let target_fields = &target_adt_def.non_enum_variant().fields; - - assert!( - coerce_index.index() < source_fields.len() - && source_fields.len() == target_fields.len() - ); + // `T` as `dyn* Trait` unsizes *directly*. + // + // FIXME(dyn_star): This case is a bit awkward, b/c we're not really computing + // a tail here. We probably should handle this separately in the *caller* of + // this function, rather than returning something that is semantically different + // than what we return above. + (_, &ty::Dynamic(_, _, ty::DynStar)) => (source_ty, target_ty), - find_vtable_types_for_unsizing( - tcx, - source_fields[coerce_index].ty(*tcx, source_args), - target_fields[coerce_index].ty(*tcx, target_args), - ) - } _ => bug!( "find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}", source_ty, @@ -1308,7 +1309,7 @@ fn visit_mentioned_item<'tcx>( } MentionedItem::UnsizeCast { source_ty, target_ty } => { let (source_ty, target_ty) = - find_vtable_types_for_unsizing(tcx.at(span), source_ty, target_ty); + find_tails_for_unsizing(tcx.at(span), source_ty, target_ty); // This could also be a different Unsize instruction, like // from a fixed sized array to a slice. But we are only // interested in things that produce a vtable. |
