Add rustc_deny_explicit_impl

This commit is contained in:
Michael Goulet 2022-11-12 23:37:52 +00:00
parent 742d3f02c2
commit b5b6467810
6 changed files with 28 additions and 50 deletions

View file

@ -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:

View file

@ -691,6 +691,10 @@ pub struct 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 \

View file

@ -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;
}
"explicit impls for the `{trait_name}` trait are not permitted"
);
err.span_label(impl_header_span, format!("impl of `{trait_name}` not allowed"));
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;
}
// 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 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;
}
if tcx.features().unboxed_closures {
// the feature gate allows all Fn traits
err.emit();
return;
}

View file

@ -1251,6 +1251,7 @@
rustc_deallocator,
rustc_def_path,
rustc_default_body_unstable,
rustc_deny_explicit_impl,
rustc_diagnostic_item,
rustc_diagnostic_macros,
rustc_dirty,

View file

@ -96,6 +96,7 @@ unsafe impl<T: Sync + ?Sized> 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<T: ?Sized> {
// Empty.
}
@ -693,6 +695,7 @@ impl<T: ?Sized> StructuralEq for PhantomData<T> {}
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<T: ?Sized> 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.

View file

@ -50,6 +50,7 @@
///
/// [`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"]