diff options
| -rw-r--r-- | compiler/rustc_hir_analysis/messages.ftl | 3 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/coherence/builtin.rs | 116 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/errors.rs | 12 | ||||
| -rw-r--r-- | library/core/src/marker.rs | 1 | ||||
| -rw-r--r-- | tests/ui/deriving/deriving-coerce-pointee-neg.rs | 26 | ||||
| -rw-r--r-- | tests/ui/deriving/deriving-coerce-pointee-neg.stderr | 91 |
6 files changed, 199 insertions, 50 deletions
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 98eb4f65e22..6badd290917 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -99,6 +99,9 @@ hir_analysis_coerce_pointee_not_struct = `derive(CoercePointee)` is only applica hir_analysis_coerce_pointee_not_transparent = `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout +hir_analysis_coerce_unsized_field_validity = for `{$ty}` to have a valid implementation of `{$trait_name}`, it must be possible to coerce the field of type `{$field_ty}` + .label = `{$field_ty}` must be a pointer, reference, or smart pointer that is allowed to be unsized + hir_analysis_coerce_unsized_may = the trait `{$trait_name}` may only be implemented for a coercion between structures hir_analysis_coerce_zero = implementing `{$trait_name}` requires a field to be coerced diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index dc9a5a3db5d..9d6bb1cf6bf 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeVisitableExt, TypingMode, suggest_constraining_type_params, }; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, Span, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::misc::{ ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason, @@ -199,6 +199,13 @@ fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), E tcx.at(span).ensure_ok().coerce_unsized_info(impl_did) } +fn is_from_coerce_pointee_derive(tcx: TyCtxt<'_>, span: Span) -> bool { + span.ctxt() + .outer_expn_data() + .macro_def_id + .is_some_and(|def_id| tcx.is_diagnostic_item(sym::CoercePointee, def_id)) +} + fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> { let tcx = checker.tcx; let impl_did = checker.impl_def_id; @@ -206,6 +213,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did); let span = tcx.def_span(impl_did); + let trait_name = "DispatchFromDyn"; let dispatch_from_dyn_trait = tcx.require_lang_item(LangItem::DispatchFromDyn, Some(span)); @@ -240,17 +248,15 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() (&RawPtr(_, a_mutbl), &RawPtr(_, b_mutbl)) if a_mutbl == b_mutbl => Ok(()), (&Adt(def_a, args_a), &Adt(def_b, args_b)) if def_a.is_struct() && def_b.is_struct() => { if def_a != def_b { - if def_a != def_b { - let source_path = tcx.def_path_str(def_a.did()); - let target_path = tcx.def_path_str(def_b.did()); - return Err(tcx.dcx().emit_err(errors::CoerceSameStruct { - span, - trait_name: "DispatchFromDyn", - note: true, - source_path, - target_path, - })); - } + let source_path = tcx.def_path_str(def_a.did()); + let target_path = tcx.def_path_str(def_b.did()); + return Err(tcx.dcx().emit_err(errors::CoerceSameStruct { + span, + trait_name, + note: true, + source_path, + target_path, + })); } if def_a.repr().c() || def_a.repr().packed() { @@ -311,40 +317,46 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() if coerced_fields.is_empty() { return Err(tcx.dcx().emit_err(errors::CoerceNoField { span, - trait_name: "DispatchFromDyn", + trait_name, note: true, })); - } else if coerced_fields.len() > 1 { - return Err(tcx.dcx().emit_err(errors::CoerceMulti { - span, - trait_name: "DispatchFromDyn", - number: coerced_fields.len(), - fields: coerced_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(), - })); - } else { + } else if let &[(_, ty_a, ty_b, field_span)] = &coerced_fields[..] { let ocx = ObligationCtxt::new_with_diagnostics(&infcx); - for (_, ty_a, ty_b, _) in coerced_fields { - ocx.register_obligation(Obligation::new( - tcx, - cause.clone(), - param_env, - ty::TraitRef::new(tcx, dispatch_from_dyn_trait, [ty_a, ty_b]), - )); - } + ocx.register_obligation(Obligation::new( + tcx, + cause.clone(), + param_env, + ty::TraitRef::new(tcx, dispatch_from_dyn_trait, [ty_a, ty_b]), + )); let errors = ocx.select_all_or_error(); if !errors.is_empty() { - return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); + if is_from_coerce_pointee_derive(tcx, span) { + return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity { + span, + trait_name, + ty: trait_ref.self_ty(), + field_span, + field_ty: ty_a, + })); + } else { + return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); + } } // Finally, resolve all regions. ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?; - } - Ok(()) + Ok(()) + } else { + return Err(tcx.dcx().emit_err(errors::CoerceMulti { + span, + trait_name, + number: coerced_fields.len(), + fields: coerced_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(), + })); + } } - _ => Err(tcx - .dcx() - .emit_err(errors::CoerceUnsizedNonStruct { span, trait_name: "DispatchFromDyn" })), + _ => Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name })), } } @@ -354,13 +366,14 @@ pub(crate) fn coerce_unsized_info<'tcx>( ) -> Result<CoerceUnsizedInfo, ErrorGuaranteed> { debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did); let span = tcx.def_span(impl_did); + let trait_name = "CoerceUnsized"; let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)); - let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span)); let source = tcx.type_of(impl_did).instantiate_identity(); let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity(); + assert_eq!(trait_ref.def_id, coerce_unsized_trait); let target = trait_ref.args.type_at(1); debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target); @@ -387,9 +400,9 @@ pub(crate) fn coerce_unsized_info<'tcx>( ) .emit(); } - (mt_a.ty, mt_b.ty, unsize_trait, None) + (mt_a.ty, mt_b.ty, unsize_trait, None, span) }; - let (source, target, trait_def_id, kind) = match (source.kind(), target.kind()) { + let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) { (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => { infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a); let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; @@ -412,7 +425,7 @@ pub(crate) fn coerce_unsized_info<'tcx>( let target_path = tcx.def_path_str(def_b.did()); return Err(tcx.dcx().emit_err(errors::CoerceSameStruct { span, - trait_name: "CoerceUnsized", + trait_name, note: true, source_path, target_path, @@ -499,7 +512,7 @@ pub(crate) fn coerce_unsized_info<'tcx>( if diff_fields.is_empty() { return Err(tcx.dcx().emit_err(errors::CoerceNoField { span, - trait_name: "CoerceUnsized", + trait_name, note: true, })); } else if diff_fields.len() > 1 { @@ -512,21 +525,19 @@ pub(crate) fn coerce_unsized_info<'tcx>( return Err(tcx.dcx().emit_err(errors::CoerceMulti { span, - trait_name: "CoerceUnsized", + trait_name, number: diff_fields.len(), fields: diff_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(), })); } - let (i, a, b, _) = diff_fields[0]; + let (i, a, b, field_span) = diff_fields[0]; let kind = ty::adjustment::CustomCoerceUnsized::Struct(i); - (a, b, coerce_unsized_trait, Some(kind)) + (a, b, coerce_unsized_trait, Some(kind), field_span) } _ => { - return Err(tcx - .dcx() - .emit_err(errors::CoerceUnsizedNonStruct { span, trait_name: "CoerceUnsized" })); + return Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name })); } }; @@ -541,8 +552,19 @@ pub(crate) fn coerce_unsized_info<'tcx>( ); ocx.register_obligation(obligation); let errors = ocx.select_all_or_error(); + if !errors.is_empty() { - return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); + if is_from_coerce_pointee_derive(tcx, span) { + return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity { + span, + trait_name, + ty: trait_ref.self_ty(), + field_span, + field_ty: source, + })); + } else { + return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); + } } // Finally, resolve all regions. diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index a74d9b95e0e..99262f9871e 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1322,6 +1322,18 @@ pub(crate) struct CoerceSameStruct { } #[derive(Diagnostic)] +#[diag(hir_analysis_coerce_unsized_field_validity)] +pub(crate) struct CoerceFieldValidity<'tcx> { + #[primary_span] + pub span: Span, + pub ty: Ty<'tcx>, + pub trait_name: &'static str, + #[label] + pub field_span: Span, + pub field_ty: Ty<'tcx>, +} + +#[derive(Diagnostic)] #[diag(hir_analysis_trait_cannot_impl_for_ty, code = E0204)] pub(crate) struct TraitCannotImplForTy { #[primary_span] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 842a48e1606..b0571bf7247 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1302,6 +1302,7 @@ pub trait FnPtr: Copy + Clone { /// ``` #[rustc_builtin_macro(CoercePointee, attributes(pointee))] #[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize, coerce_pointee_validated)] +#[cfg_attr(not(test), rustc_diagnostic_item = "CoercePointee")] #[unstable(feature = "derive_coerce_pointee", issue = "123430")] pub macro CoercePointee($item:item) { /* compiler built-in */ diff --git a/tests/ui/deriving/deriving-coerce-pointee-neg.rs b/tests/ui/deriving/deriving-coerce-pointee-neg.rs index 6577500d8eb..e660e7baacb 100644 --- a/tests/ui/deriving/deriving-coerce-pointee-neg.rs +++ b/tests/ui/deriving/deriving-coerce-pointee-neg.rs @@ -142,4 +142,30 @@ struct TryToWipeRepr<'a, #[pointee] T: ?Sized> { ptr: &'a T, } +#[repr(transparent)] +#[derive(CoercePointee)] +//~^ ERROR for `RcWithId<T>` to have a valid implementation of `CoerceUnsized`, it must be possible to coerce the field of type `Rc<(i32, Box<T>)>` +//~| ERROR for `RcWithId<T>` to have a valid implementation of `DispatchFromDyn`, it must be possible to coerce the field of type `Rc<(i32, Box<T>)>` +struct RcWithId<T: ?Sized> { + inner: std::rc::Rc<(i32, Box<T>)>, +} + +#[repr(transparent)] +#[derive(CoercePointee)] +//~^ ERROR implementing `CoerceUnsized` does not allow multiple fields to be coerced +//~| ERROR implementing `DispatchFromDyn` does not allow multiple fields to be coerced +struct MoreThanOneField<T: ?Sized> { + //~^ ERROR transparent struct needs at most one field with non-trivial size or alignment, but has 2 + inner1: Box<T>, + inner2: Box<T>, +} + +struct NotCoercePointeeData<T: ?Sized>(T); + +#[repr(transparent)] +#[derive(CoercePointee)] +//~^ ERROR for `UsingNonCoercePointeeData<T>` to have a valid implementation of `CoerceUnsized`, it must be possible to coerce the field of type `NotCoercePointeeData<T>` +//~| ERROR for `UsingNonCoercePointeeData<T>` to have a valid implementation of `DispatchFromDyn`, it must be possible to coerce the field of type `NotCoercePointeeData<T>` +struct UsingNonCoercePointeeData<T: ?Sized>(NotCoercePointeeData<T>); + fn main() {} diff --git a/tests/ui/deriving/deriving-coerce-pointee-neg.stderr b/tests/ui/deriving/deriving-coerce-pointee-neg.stderr index 999214bfa9f..e346d13ff5c 100644 --- a/tests/ui/deriving/deriving-coerce-pointee-neg.stderr +++ b/tests/ui/deriving/deriving-coerce-pointee-neg.stderr @@ -118,7 +118,92 @@ error[E0802]: `derive(CoercePointee)` is only applicable to `struct` with `repr( LL | struct TryToWipeRepr<'a, #[pointee] T: ?Sized> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 17 previous errors +error: for `RcWithId<T>` to have a valid implementation of `DispatchFromDyn`, it must be possible to coerce the field of type `Rc<(i32, Box<T>)>` + --> $DIR/deriving-coerce-pointee-neg.rs:146:10 + | +LL | #[derive(CoercePointee)] + | ^^^^^^^^^^^^^ +... +LL | inner: std::rc::Rc<(i32, Box<T>)>, + | --------------------------------- `Rc<(i32, Box<T>)>` must be a pointer, reference, or smart pointer that is allowed to be unsized + | + = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0375]: implementing `DispatchFromDyn` does not allow multiple fields to be coerced + --> $DIR/deriving-coerce-pointee-neg.rs:154:10 + | +LL | #[derive(CoercePointee)] + | ^^^^^^^^^^^^^ + | +note: the trait `DispatchFromDyn` may only be implemented when a single field is being coerced + --> $DIR/deriving-coerce-pointee-neg.rs:159:5 + | +LL | inner1: Box<T>, + | ^^^^^^^^^^^^^^ +LL | inner2: Box<T>, + | ^^^^^^^^^^^^^^ + = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: for `UsingNonCoercePointeeData<T>` to have a valid implementation of `DispatchFromDyn`, it must be possible to coerce the field of type `NotCoercePointeeData<T>` + --> $DIR/deriving-coerce-pointee-neg.rs:166:10 + | +LL | #[derive(CoercePointee)] + | ^^^^^^^^^^^^^ +... +LL | struct UsingNonCoercePointeeData<T: ?Sized>(NotCoercePointeeData<T>); + | ----------------------- `NotCoercePointeeData<T>` must be a pointer, reference, or smart pointer that is allowed to be unsized + | + = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: for `RcWithId<T>` to have a valid implementation of `CoerceUnsized`, it must be possible to coerce the field of type `Rc<(i32, Box<T>)>` + --> $DIR/deriving-coerce-pointee-neg.rs:146:10 + | +LL | #[derive(CoercePointee)] + | ^^^^^^^^^^^^^ +... +LL | inner: std::rc::Rc<(i32, Box<T>)>, + | --------------------------------- `Rc<(i32, Box<T>)>` must be a pointer, reference, or smart pointer that is allowed to be unsized + | + = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0375]: implementing `CoerceUnsized` does not allow multiple fields to be coerced + --> $DIR/deriving-coerce-pointee-neg.rs:154:10 + | +LL | #[derive(CoercePointee)] + | ^^^^^^^^^^^^^ + | +note: the trait `CoerceUnsized` may only be implemented when a single field is being coerced + --> $DIR/deriving-coerce-pointee-neg.rs:159:5 + | +LL | inner1: Box<T>, + | ^^^^^^^^^^^^^^ +LL | inner2: Box<T>, + | ^^^^^^^^^^^^^^ + = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: for `UsingNonCoercePointeeData<T>` to have a valid implementation of `CoerceUnsized`, it must be possible to coerce the field of type `NotCoercePointeeData<T>` + --> $DIR/deriving-coerce-pointee-neg.rs:166:10 + | +LL | #[derive(CoercePointee)] + | ^^^^^^^^^^^^^ +... +LL | struct UsingNonCoercePointeeData<T: ?Sized>(NotCoercePointeeData<T>); + | ----------------------- `NotCoercePointeeData<T>` must be a pointer, reference, or smart pointer that is allowed to be unsized + | + = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0690]: transparent struct needs at most one field with non-trivial size or alignment, but has 2 + --> $DIR/deriving-coerce-pointee-neg.rs:157:1 + | +LL | struct MoreThanOneField<T: ?Sized> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ needs at most one field with non-trivial size or alignment, but has 2 +LL | +LL | inner1: Box<T>, + | -------------- this field has non-zero size or requires alignment +LL | inner2: Box<T>, + | -------------- this field has non-zero size or requires alignment + +error: aborting due to 24 previous errors -Some errors have detailed explanations: E0392, E0802. -For more information about an error, try `rustc --explain E0392`. +Some errors have detailed explanations: E0375, E0392, E0690, E0802. +For more information about an error, try `rustc --explain E0375`. |
