diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index d3a2c4d20f95d..e39dc37ece3a7 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -4,7 +4,7 @@ use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::{self, PseudoCanonicalInput, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::{Normalized, ObligationCause}; -use tracing::debug; +use tracing::{debug, instrument}; pub(crate) fn provide(p: &mut Providers) { *p = Providers { @@ -17,6 +17,7 @@ pub(crate) fn provide(p: &mut Providers) { }; } +#[instrument(level = "debug", skip(tcx))] fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable> + PartialEq + Copy>( tcx: TyCtxt<'tcx>, goal: PseudoCanonicalInput<'tcx, T>, diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index bb25a14ef7443..e45617f53b25b 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -6,13 +6,13 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::{ - self, SizedTraitKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast, - fold_regions, + self, SizedTraitKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, TypingEnv, + Upcast, fold_regions, }; use rustc_span::DUMMY_SP; use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_trait_selection::traits; -use tracing::instrument; +use tracing::{debug, instrument}; /// If `ty` implements the given `sizedness` trait, returns `None`. Otherwise, returns the type /// that must implement the given `sizedness` for `ty` to implement it. @@ -298,6 +298,7 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Asyncness { }) } +#[instrument(level = "debug", skip(tcx))] fn unsizing_params_for_adt<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> DenseBitSet { let def = tcx.adt_def(def_id); let num_params = tcx.generics_of(def_id).count(); @@ -332,7 +333,16 @@ fn unsizing_params_for_adt<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> DenseBitSe // Ensure none of the other fields mention the parameters used // in unsizing. for field in prefix_fields { - for arg in tcx.type_of(field.did).instantiate_identity().walk() { + let field_ty = tcx.type_of(field.did).instantiate_identity(); + let field_ty = tcx + .try_normalize_erasing_regions(TypingEnv::non_body_analysis(tcx, def_id), field_ty) + .inspect(|r| debug!(?r)) + .unwrap_or(field_ty); + debug!(?field_ty); + if field_ty.is_phantom_data() { + continue; + } + for arg in field_ty.walk() { if let Some(i) = maybe_unsizing_param_idx(arg) { unsizing_params.remove(i); } diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 5ecc2a63ea837..be3a73810319f 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -218,7 +218,7 @@ pub trait PointeeSized { /// - Structs `Foo<..., T1, ..., Tn, ...>` implement `Unsize>` /// where any number of (type and const) parameters may be changed if all of these conditions /// are met: -/// - Only the last field of `Foo` has a type involving the parameters `T1`, ..., `Tn`. +/// - Other than `PhantomData<_>` fields, only the last field of `Foo` has a type involving the parameters `T1`, ..., `Tn`. /// - All other parameters of the struct are equal. /// - `Field: Unsize>`, where `Field<...>` stands for the actual /// type of the struct's last field. diff --git a/tests/ui/traits/dispatch-from-dyn-invalid-impls.rs b/tests/ui/traits/dispatch-from-dyn-invalid-impls.rs index f5f66ca69cfc1..a3ed983a1d88b 100644 --- a/tests/ui/traits/dispatch-from-dyn-invalid-impls.rs +++ b/tests/ui/traits/dispatch-from-dyn-invalid-impls.rs @@ -68,4 +68,16 @@ where { } +struct Ptr(Box); + +impl<'a, T: ?Sized, U: ?Sized> DispatchFromDyn<&'a Ptr> for &'a Ptr {} +//~^ ERROR conflicting implementations of trait `DispatchFromDyn<&Ptr<_>>` for type `&Ptr<_>` + +struct Inner(T); +#[repr(transparent)] +struct Outer(PhantomData, Inner); + +impl<'a, T: Unsize + ?Sized, U: ?Sized> DispatchFromDyn<&'a Outer> for &'a Outer {} +//~^ ERROR conflicting implementations of trait `DispatchFromDyn<&Outer<_>>` for type `&Outer<_>` + fn main() {} diff --git a/tests/ui/traits/dispatch-from-dyn-invalid-impls.stderr b/tests/ui/traits/dispatch-from-dyn-invalid-impls.stderr index 676da0ce81fb1..618e8906a3341 100644 --- a/tests/ui/traits/dispatch-from-dyn-invalid-impls.stderr +++ b/tests/ui/traits/dispatch-from-dyn-invalid-impls.stderr @@ -1,3 +1,24 @@ +error[E0119]: conflicting implementations of trait `DispatchFromDyn<&Ptr<_>>` for type `&Ptr<_>` + --> $DIR/dispatch-from-dyn-invalid-impls.rs:73:1 + | +LL | impl<'a, T: ?Sized, U: ?Sized> DispatchFromDyn<&'a Ptr> for &'a Ptr {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl<'a, T, U> DispatchFromDyn<&'a U> for &'a T + where T: Unsize, T: ?Sized, U: ?Sized; + = note: downstream crates may implement trait `std::marker::Unsize>` for type `std::boxed::Box<_>` + +error[E0119]: conflicting implementations of trait `DispatchFromDyn<&Outer<_>>` for type `&Outer<_>` + --> $DIR/dispatch-from-dyn-invalid-impls.rs:80:1 + | +LL | impl<'a, T: Unsize + ?Sized, U: ?Sized> DispatchFromDyn<&'a Outer> for &'a Outer {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl<'a, T, U> DispatchFromDyn<&'a U> for &'a T + where T: Unsize, T: ?Sized, U: ?Sized; + error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else --> $DIR/dispatch-from-dyn-invalid-impls.rs:19:1 | @@ -54,7 +75,7 @@ LL | | T: Unsize | = note: extra field `1` of type `OverAlignedZst` is not allowed -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0374, E0375, E0378. -For more information about an error, try `rustc --explain E0374`. +Some errors have detailed explanations: E0119, E0374, E0375, E0378. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/unsized/unsize-with-phantom.rs b/tests/ui/unsized/unsize-with-phantom.rs new file mode 100644 index 0000000000000..8cc8790778394 --- /dev/null +++ b/tests/ui/unsized/unsize-with-phantom.rs @@ -0,0 +1,41 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +#![feature(unsize)] + +use std::marker::{PhantomData, Unsize}; + +fn assert() +where + A: Unsize, +{ +} + +struct Ptr(PhantomData, A); + +trait ToPhantom { + type T; +} +impl ToPhantom for T { + type T = PhantomData Self>; +} + +struct Ptr2(::T, A); + +trait Identity { + type T; +} + +impl Identity for T { + type T = T; +} + +struct Ptr3( A> as Identity>::T, A); + +fn main() { + assert::, Ptr<[u8]>>(); + assert::, Ptr2<[u8]>>(); + assert::, Ptr3<[u8]>>(); +}