diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs index 697ef7bc022..1608550aa6a 100644 --- a/compiler/rustc_typeck/src/coherence/orphan.rs +++ b/compiler/rustc_typeck/src/coherence/orphan.rs @@ -3,7 +3,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; -use rustc_errors::ErrorGuaranteed; +use rustc_errors::{Diagnostic, ErrorGuaranteed}; use rustc_hir as hir; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::ty::subst::GenericArgKind; @@ -107,6 +107,7 @@ fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) { Err(err) => emit_orphan_check_error( tcx, sp, + item.span, tr.path.span, trait_ref.self_ty(), impl_.self_ty.span, @@ -207,6 +208,7 @@ fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) { fn emit_orphan_check_error<'tcx>( tcx: TyCtxt<'tcx>, sp: Span, + full_impl_span: Span, trait_span: Span, self_ty: Ty<'tcx>, self_ty_span: Span, @@ -247,8 +249,20 @@ fn emit_orphan_check_error<'tcx>( ty::Slice(_) => (this, " because slices are always foreign"), ty::Array(..) => (this, " because arrays are always foreign"), ty::Tuple(..) => (this, " because tuples are always foreign"), + ty::RawPtr(ptr_ty) => { + emit_newtype_suggestion_for_raw_ptr( + full_impl_span, + self_ty, + self_ty_span, + ptr_ty, + &mut err, + ); + + (format!("`{}`", ty), " because raw pointers are always foreign") + } _ => (format!("`{}`", ty), ""), }; + let msg = format!("{} is not defined in the current crate{}", ty, postfix); if *is_target_ty { // Point at `D` in `impl for C in D` @@ -330,6 +344,27 @@ fn emit_orphan_check_error<'tcx>( }) } +fn emit_newtype_suggestion_for_raw_ptr( + full_impl_span: Span, + self_ty: Ty<'_>, + self_ty_span: Span, + ptr_ty: &ty::TypeAndMut<'_>, + diag: &mut Diagnostic, +) { + if !self_ty.needs_subst() { + let mut_key = if ptr_ty.mutbl == rustc_middle::mir::Mutability::Mut { "mut " } else { "" }; + let msg_sugg = "consider introducing a new wrapper type".to_owned(); + let sugg = vec![ + ( + full_impl_span.shrink_to_lo(), + format!("struct WrapperType(*{}{});\n\n", mut_key, ptr_ty.ty), + ), + (self_ty_span, "WrapperType".to_owned()), + ]; + diag.multipart_suggestion(msg_sugg, sugg, rustc_errors::Applicability::MaybeIncorrect); + } +} + /// Lint impls of auto traits if they are likely to have /// unsound or surprising effects on auto impls. fn lint_auto_trait_impl<'tcx>( diff --git a/src/test/ui/errors/issue-99572-impl-trait-on-pointer.rs b/src/test/ui/errors/issue-99572-impl-trait-on-pointer.rs new file mode 100644 index 00000000000..272c6bd3fb7 --- /dev/null +++ b/src/test/ui/errors/issue-99572-impl-trait-on-pointer.rs @@ -0,0 +1,25 @@ +// Emit additional suggestion to correct the trait implementation +// on a pointer +use std::{fmt, marker}; + +struct LocalType; + +impl fmt::Display for *mut LocalType { +//~^ ERROR only traits defined in the current crate can be implemented for arbitrary types +//~| NOTE impl doesn't use only types from inside the current crate +//~| NOTE `*mut LocalType` is not defined in the current crate because raw pointers are always foreign +//~| NOTE define and implement a trait or new type instead +//~| HELP consider introducing a new wrapper type + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "This not compile") + } +} + +impl marker::Copy for *mut T { +//~^ ERROR only traits defined in the current crate can be implemented for arbitrary types +//~| NOTE impl doesn't use only types from inside the current crate +//~| NOTE `*mut T` is not defined in the current crate because raw pointers are always foreign +//~| NOTE define and implement a trait or new type instead +} + +fn main() {} diff --git a/src/test/ui/errors/issue-99572-impl-trait-on-pointer.stderr b/src/test/ui/errors/issue-99572-impl-trait-on-pointer.stderr new file mode 100644 index 00000000000..78d7a47deaa --- /dev/null +++ b/src/test/ui/errors/issue-99572-impl-trait-on-pointer.stderr @@ -0,0 +1,31 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/issue-99572-impl-trait-on-pointer.rs:7:1 + | +LL | impl fmt::Display for *mut LocalType { + | ^^^^^^^^^^^^^^^^^^^^^^-------------- + | | | + | | `*mut LocalType` is not defined in the current crate because raw pointers are always foreign + | impl doesn't use only types from inside the current crate + | + = note: define and implement a trait or new type instead +help: consider introducing a new wrapper type + | +LL + struct WrapperType(*mut LocalType); +LL + +LL ~ impl fmt::Display for WrapperType { + | + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/issue-99572-impl-trait-on-pointer.rs:18:1 + | +LL | impl marker::Copy for *mut T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^------ + | | | + | | `*mut T` is not defined in the current crate because raw pointers are always foreign + | impl doesn't use only types from inside the current crate + | + = note: define and implement a trait or new type instead + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0117`.