diff --git a/compiler/rustc_error_codes/src/error_codes/E0322.md b/compiler/rustc_error_codes/src/error_codes/E0322.md index ccef8681dd601..194bbd83b0f74 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0322.md +++ b/compiler/rustc_error_codes/src/error_codes/E0322.md @@ -1,4 +1,5 @@ -The `Sized` trait was implemented explicitly. +A built-in trait was implemented explicitly. All implementations of the trait +are provided automatically by the compiler. Erroneous code example: diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 01477265f6175..4b6e068db4312 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -691,6 +691,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: true, "#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl." ), + rustc_attr!( + rustc_deny_explicit_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: false, + "#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls" + ), rustc_attr!( rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word), ErrorFollowing, "#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \ diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index ae9ebe5909144..1bf3768fead36 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -5,10 +5,11 @@ // done by the orphan and overlap modules. Then we build up various // mappings. That mapping code resides here. -use rustc_errors::struct_span_err; +use rustc_errors::{error_code, struct_span_err}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; +use rustc_span::sym; use rustc_trait_selection::traits; mod builtin; @@ -39,61 +40,26 @@ fn enforce_trait_manually_implementable( impl_def_id: LocalDefId, trait_def_id: DefId, ) { - let did = Some(trait_def_id); - let li = tcx.lang_items(); let impl_header_span = tcx.def_span(impl_def_id); - // Disallow *all* explicit impls of `Pointee`, `DiscriminantKind`, `Sized` and `Unsize` for now. - if did == li.pointee_trait() { - struct_span_err!( + // Disallow *all* explicit impls of traits marked `#[rustc_deny_explicit_impl]` + if tcx.has_attr(trait_def_id, sym::rustc_deny_explicit_impl) { + let trait_name = tcx.item_name(trait_def_id); + let mut err = struct_span_err!( tcx.sess, impl_header_span, E0322, - "explicit impls for the `Pointee` trait are not permitted" - ) - .span_label(impl_header_span, "impl of `Pointee` not allowed") - .emit(); - return; - } - - if did == li.discriminant_kind_trait() { - struct_span_err!( - tcx.sess, - impl_header_span, - E0322, - "explicit impls for the `DiscriminantKind` trait are not permitted" - ) - .span_label(impl_header_span, "impl of `DiscriminantKind` not allowed") - .emit(); - return; - } - - if did == li.sized_trait() { - struct_span_err!( - tcx.sess, - impl_header_span, - E0322, - "explicit impls for the `Sized` trait are not permitted" - ) - .span_label(impl_header_span, "impl of `Sized` not allowed") - .emit(); - return; - } - - if did == li.unsize_trait() { - struct_span_err!( - tcx.sess, - impl_header_span, - E0328, - "explicit impls for the `Unsize` trait are not permitted" - ) - .span_label(impl_header_span, "impl of `Unsize` not allowed") - .emit(); - return; - } + "explicit impls for the `{trait_name}` trait are not permitted" + ); + err.span_label(impl_header_span, format!("impl of `{trait_name}` not allowed")); + + // Maintain explicit error code for `Unsize`, since it has a useful + // explanation about using `CoerceUnsized` instead. + if Some(trait_def_id) == tcx.lang_items().unsize_trait() { + err.code(error_code!(E0328)); + } - if tcx.features().unboxed_closures { - // the feature gate allows all Fn traits + err.emit(); return; } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index bad6d58790708..a56450a3573d1 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1210,6 +1210,7 @@ symbols! { rustc_deallocator, rustc_def_path, rustc_default_body_unstable, + rustc_deny_explicit_impl, rustc_diagnostic_item, rustc_diagnostic_macros, rustc_dirty, diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index ae4ebf4444295..3eff6033f8da9 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -96,6 +96,7 @@ unsafe impl Send for &T {} )] #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable #[rustc_specialization_trait] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] pub trait Sized { // Empty. } @@ -127,6 +128,7 @@ pub trait Sized { /// [nomicon-coerce]: ../../nomicon/coercions.html #[unstable(feature = "unsize", issue = "27732")] #[lang = "unsize"] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] pub trait Unsize { // Empty. } @@ -693,6 +695,7 @@ impl StructuralEq for PhantomData {} reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead" )] #[lang = "discriminant_kind"] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] pub trait DiscriminantKind { /// The type of the discriminant, which must satisfy the trait /// bounds required by `mem::Discriminant`. @@ -793,6 +796,7 @@ impl Unpin for *mut T {} #[lang = "destruct"] #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] #[const_trait] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] pub trait Destruct {} /// A marker for tuple types. @@ -802,6 +806,7 @@ pub trait Destruct {} #[unstable(feature = "tuple_trait", issue = "none")] #[lang = "tuple_trait"] #[rustc_on_unimplemented(message = "`{Self}` is not a tuple")] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] pub trait Tuple {} /// Implementations of `Copy` for primitive types. diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index caa10f1818b4d..a8604843e9631 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -50,6 +50,7 @@ use crate::hash::{Hash, Hasher}; /// /// [`to_raw_parts`]: *const::to_raw_parts #[lang = "pointee_trait"] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] pub trait Pointee { /// The type for metadata in pointers and references to `Self`. #[lang = "metadata_type"]