Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,14 @@ pub(crate) fn expand_deriving_eq(
additional_bounds: Vec::new(),
supports_unions: true,
methods: vec![MethodDef {
name: sym::assert_receiver_is_total_eq,
name: sym::assert_fields_are_eq,
generics: Bounds::empty(),
explicit_self: true,
nonself_args: vec![],
ret_ty: Unit,
attributes: thin_vec![
cx.attr_word(sym::inline, span),
cx.attr_nested_word(sym::doc, sym::hidden, span),
cx.attr_nested_word(sym::coverage, sym::off, span)
cx.attr_nested_word(sym::coverage, sym::off, span),
],
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
Expand Down
64 changes: 61 additions & 3 deletions compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,11 @@ use rustc_ast_pretty::pprust::expr_to_string;
use rustc_attr_parsing::AttributeParser;
use rustc_errors::{Applicability, LintDiagnostic, inline_fluent};
use rustc_feature::GateIssue;
use rustc_hir as hir;
use rustc_hir::attrs::{AttributeKind, DocAttribute};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
use rustc_hir::intravisit::FnKind as HirFnKind;
use rustc_hir::{Body, FnDecl, ImplItemImplKind, PatKind, PredicateOrigin, find_attr};
use rustc_hir::{self as hir, Body, FnDecl, ImplItemImplKind, PatKind, PredicateOrigin, find_attr};
use rustc_middle::bug;
use rustc_middle::lint::LevelAndSource;
use rustc_middle::ty::layout::LayoutOf;
Expand Down Expand Up @@ -59,7 +58,7 @@ use crate::lints::{
BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasBounds,
BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub,
BuiltinUnreachablePub, BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment,
BuiltinUnusedDocCommentSub, BuiltinWhileTrue, InvalidAsmLabel,
BuiltinUnusedDocCommentSub, BuiltinWhileTrue, EqInternalMethodImplemented, InvalidAsmLabel,
};
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext};
declare_lint! {
Expand Down Expand Up @@ -3188,3 +3187,62 @@ impl EarlyLintPass for SpecialModuleName {
}
}
}

declare_lint! {
/// The `internal_eq_trait_method_impls` lint detects manual
/// implementations of `Eq::assert_receiver_is_total_eq`.
///
/// ### Example
///
/// ```rust
/// #[derive(PartialEq)]
/// pub struct Foo;
///
/// impl Eq for Foo {
/// fn assert_receiver_is_total_eq(&self) {}
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// This method exists so that `#[derive(Eq)]` can check that all
/// fields of a type implement `Eq`. Other users were never supposed
/// to implement it and it was hidden from documentation.
///
/// Unfortunately, it was not explicitly marked as unstable and some
/// people have now mistakenly assumed they had to implement this method.
///
/// As the method is never called by the standard library, you can safely
/// remove any implementations of the method and just write `impl Eq for Foo {}`.
///
/// This is a [future-incompatible] lint to transition this to a hard
/// error in the future. See [issue #152336] for more details.
///
/// [issue #152336]: https://github.com/rust-lang/rust/issues/152336
pub INTERNAL_EQ_TRAIT_METHOD_IMPLS,
Warn,
"manual implementation of the internal `Eq::assert_receiver_is_total_eq` method",
@future_incompatible = FutureIncompatibleInfo {
reason: fcw!(FutureReleaseError #152336),
report_in_deps: false,
};
}

declare_lint_pass!(InternalEqTraitMethodImpls => [INTERNAL_EQ_TRAIT_METHOD_IMPLS]);

impl<'tcx> LateLintPass<'tcx> for InternalEqTraitMethodImpls {
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx rustc_hir::ImplItem<'tcx>) {
if let ImplItemImplKind::Trait { defaultness: _, trait_item_def_id: Ok(trait_item_def_id) } =
item.impl_kind
&& cx.tcx.is_diagnostic_item(sym::assert_receiver_is_total_eq, trait_item_def_id)
{
cx.emit_span_lint(
INTERNAL_EQ_TRAIT_METHOD_IMPLS,
item.span,
EqInternalMethodImplemented,
);
}
}
}
1 change: 1 addition & 0 deletions compiler/rustc_lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ late_lint_methods!(
FunctionCastsAsInteger: FunctionCastsAsInteger,
CheckTransmutes: CheckTransmutes,
LifetimeSyntax: LifetimeSyntax,
InternalEqTraitMethodImpls: InternalEqTraitMethodImpls,
]
]
);
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3883,3 +3883,8 @@ pub(crate) struct UnreachableCfgSelectPredicateWildcard {
#[label("always matches")]
pub wildcard_span: Span,
}

#[derive(LintDiagnostic)]
#[diag("`Eq::assert_receiver_is_total_eq` should never be implemented by hand")]
#[note("this method is only used to add checks to the `Eq` derive macro")]
pub(crate) struct EqInternalMethodImplemented;
2 changes: 2 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,7 @@ symbols! {
assert,
assert_eq,
assert_eq_macro,
assert_fields_are_eq,
assert_inhabited,
assert_macro,
assert_mem_uninitialized_valid,
Expand Down Expand Up @@ -1292,6 +1293,7 @@ symbols! {
integer_: "integer", // underscore to avoid clashing with the function `sym::integer` below
integral,
internal,
internal_eq_trait_method_impls,
internal_features,
into_async_iter_into_iter,
into_future,
Expand Down
17 changes: 14 additions & 3 deletions library/core/src/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,16 +336,27 @@ pub macro PartialEq($item:item) {
#[rustc_diagnostic_item = "Eq"]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
pub const trait Eq: [const] PartialEq<Self> + PointeeSized {
// this method is used solely by `impl Eq or #[derive(Eq)]` to assert that every component of a
// type implements `Eq` itself. The current deriving infrastructure means doing this assertion
// without using a method on this trait is nearly impossible.
// This method was used solely by `#[derive(Eq)]` to assert that every component of a
// type implements `Eq` itself.
//
// This should never be implemented by hand.
#[doc(hidden)]
#[coverage(off)]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "assert_receiver_is_total_eq"]
#[deprecated(
since = "CURRENT_RUSTC_VERSION",
note = "implementation detail of `#[derive(Eq)]`"
)]
fn assert_receiver_is_total_eq(&self) {}

// FIXME (#152504): this method is used solely by `#[derive(Eq)]` to assert that
// every component of a type implements `Eq` itself. It will be removed again soon.
#[doc(hidden)]
#[coverage(off)]
#[unstable(feature = "derive_eq_internals", issue = "none")]
fn assert_fields_are_eq(&self) {}
}

/// Derive macro generating an impl of the trait [`Eq`].
Expand Down
48 changes: 16 additions & 32 deletions tests/ui/deriving/deriving-all-codegen.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,9 @@ impl ::core::cmp::PartialEq for Empty {
}
#[automatically_derived]
impl ::core::cmp::Eq for Empty {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {}
fn assert_fields_are_eq(&self) {}
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for Empty {
Expand Down Expand Up @@ -139,10 +138,9 @@ impl ::core::cmp::PartialEq for Point {
}
#[automatically_derived]
impl ::core::cmp::Eq for Point {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<u32>;
}
}
Expand Down Expand Up @@ -227,10 +225,9 @@ impl ::core::cmp::PartialEq for PackedPoint {
}
#[automatically_derived]
impl ::core::cmp::Eq for PackedPoint {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<u32>;
}
}
Expand Down Expand Up @@ -310,10 +307,9 @@ impl ::core::cmp::PartialEq for TupleSingleField {
}
#[automatically_derived]
impl ::core::cmp::Eq for TupleSingleField {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<u32>;
}
}
Expand Down Expand Up @@ -385,10 +381,9 @@ impl ::core::cmp::PartialEq for SingleField {
}
#[automatically_derived]
impl ::core::cmp::Eq for SingleField {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<bool>;
}
}
Expand Down Expand Up @@ -490,10 +485,9 @@ impl ::core::cmp::PartialEq for Big {
}
#[automatically_derived]
impl ::core::cmp::Eq for Big {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<u32>;
}
}
Expand Down Expand Up @@ -754,10 +748,9 @@ impl ::core::cmp::PartialEq for Unsized {
}
#[automatically_derived]
impl ::core::cmp::Eq for Unsized {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<[u32]>;
}
}
Expand Down Expand Up @@ -849,10 +842,9 @@ impl<T: ::core::cmp::PartialEq + Trait, U: ::core::cmp::PartialEq>
#[automatically_derived]
impl<T: ::core::cmp::Eq + Trait, U: ::core::cmp::Eq> ::core::cmp::Eq for
Generic<T, U> where T::A: ::core::cmp::Eq {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<T>;
let _: ::core::cmp::AssertParamIsEq<T::A>;
let _: ::core::cmp::AssertParamIsEq<U>;
Expand Down Expand Up @@ -971,10 +963,9 @@ impl<T: ::core::cmp::PartialEq + ::core::marker::Copy + Trait,
impl<T: ::core::cmp::Eq + ::core::marker::Copy + Trait, U: ::core::cmp::Eq +
::core::marker::Copy> ::core::cmp::Eq for PackedGeneric<T, U> where
T::A: ::core::cmp::Eq + ::core::marker::Copy {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<T>;
let _: ::core::cmp::AssertParamIsEq<T::A>;
let _: ::core::cmp::AssertParamIsEq<U>;
Expand Down Expand Up @@ -1056,10 +1047,9 @@ impl ::core::cmp::PartialEq for Enum0 {
}
#[automatically_derived]
impl ::core::cmp::Eq for Enum0 {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {}
fn assert_fields_are_eq(&self) {}
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for Enum0 {
Expand Down Expand Up @@ -1126,10 +1116,9 @@ impl ::core::cmp::PartialEq for Enum1 {
}
#[automatically_derived]
impl ::core::cmp::Eq for Enum1 {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<u32>;
}
}
Expand Down Expand Up @@ -1192,10 +1181,9 @@ impl ::core::cmp::PartialEq for Fieldless1 {
}
#[automatically_derived]
impl ::core::cmp::Eq for Fieldless1 {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {}
fn assert_fields_are_eq(&self) {}
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for Fieldless1 {
Expand Down Expand Up @@ -1269,10 +1257,9 @@ impl ::core::cmp::PartialEq for Fieldless {
}
#[automatically_derived]
impl ::core::cmp::Eq for Fieldless {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {}
fn assert_fields_are_eq(&self) {}
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for Fieldless {
Expand Down Expand Up @@ -1379,10 +1366,9 @@ impl ::core::cmp::PartialEq for Mixed {
}
#[automatically_derived]
impl ::core::cmp::Eq for Mixed {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<u32>;
let _: ::core::cmp::AssertParamIsEq<Option<u32>>;
let _: ::core::cmp::AssertParamIsEq<Option<i32>>;
Expand Down Expand Up @@ -1577,10 +1563,9 @@ impl ::core::cmp::PartialEq for Fielded {
}
#[automatically_derived]
impl ::core::cmp::Eq for Fielded {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<u32>;
let _: ::core::cmp::AssertParamIsEq<bool>;
let _: ::core::cmp::AssertParamIsEq<Option<i32>>;
Expand Down Expand Up @@ -1699,10 +1684,9 @@ impl<T: ::core::cmp::PartialEq, U: ::core::cmp::PartialEq>
#[automatically_derived]
impl<T: ::core::cmp::Eq, U: ::core::cmp::Eq> ::core::cmp::Eq for
EnumGeneric<T, U> {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<T>;
let _: ::core::cmp::AssertParamIsEq<U>;
}
Expand Down
Loading
Loading