@@ -24,12 +24,11 @@ use rustc_ast_pretty::pprust::expr_to_string;
2424use rustc_attr_parsing:: AttributeParser ;
2525use rustc_errors:: { Applicability , LintDiagnostic } ;
2626use rustc_feature:: GateIssue ;
27- use rustc_hir as hir;
2827use rustc_hir:: attrs:: { AttributeKind , DocAttribute } ;
2928use rustc_hir:: def:: { DefKind , Res } ;
3029use rustc_hir:: def_id:: { CRATE_DEF_ID , DefId , LocalDefId } ;
3130use rustc_hir:: intravisit:: FnKind as HirFnKind ;
32- use rustc_hir:: { Body , FnDecl , ImplItemImplKind , PatKind , PredicateOrigin , find_attr} ;
31+ use rustc_hir:: { self as hir , Body , FnDecl , ImplItemImplKind , PatKind , PredicateOrigin , find_attr} ;
3332use rustc_middle:: bug;
3433use rustc_middle:: lint:: LevelAndSource ;
3534use rustc_middle:: ty:: layout:: LayoutOf ;
@@ -59,7 +58,7 @@ use crate::lints::{
5958 BuiltinSpecialModuleNameUsed , BuiltinTrivialBounds , BuiltinTypeAliasBounds ,
6059 BuiltinUngatedAsyncFnTrackCaller , BuiltinUnpermittedTypeInit , BuiltinUnpermittedTypeInitSub ,
6160 BuiltinUnreachablePub , BuiltinUnsafe , BuiltinUnstableFeatures , BuiltinUnusedDocComment ,
62- BuiltinUnusedDocCommentSub , BuiltinWhileTrue , InvalidAsmLabel ,
61+ BuiltinUnusedDocCommentSub , BuiltinWhileTrue , EqInternalMethodImplemented , InvalidAsmLabel ,
6362} ;
6463use crate :: {
6564 EarlyContext , EarlyLintPass , LateContext , LateLintPass , Level , LintContext ,
@@ -3191,3 +3190,64 @@ impl EarlyLintPass for SpecialModuleName {
31913190 }
31923191 }
31933192}
3193+
3194+ declare_lint ! {
3195+ /// The `eq_assert_receiver_is_total_eq_impl` lint detects manual
3196+ /// implementations of `Eq::assert_receiver_is_total_eq`.
3197+ ///
3198+ /// ### Example
3199+ ///
3200+ /// ```rust
3201+ /// #[derive(PartialEq)]
3202+ /// pub struct Foo;
3203+ ///
3204+ /// impl Eq for Foo {
3205+ /// fn assert_receiver_is_total_eq(&self) {}
3206+ /// }
3207+ /// ```
3208+ ///
3209+ /// {{produces}}
3210+ ///
3211+ /// ### Explanation
3212+ ///
3213+ /// This method exists so that `#[derive(Eq)]` can check that all
3214+ /// fields of a type implement `Eq`. Other users were never supposed
3215+ /// to implement it and it was hidden from documentation.
3216+ ///
3217+ /// Unfortunately, it was not explicitly marked as unstable and some
3218+ /// people have now mistakenly assumed they had to implement this method.
3219+ ///
3220+ /// As the method is never called by the standard library, you can safely
3221+ /// remove any implementations of the method and just write `impl Eq for Foo {}`.
3222+ ///
3223+ /// This is a [future-incompatible] lint to transition this to a hard
3224+ /// error in the future. See [issue #150000] for more details.
3225+ ///
3226+ /// [issue #150000]: https://github.com/rust-lang/rust/issues/150000
3227+ pub EQ_ASSERT_RECEIVER_IS_TOTAL_EQ_IMPL ,
3228+ Warn ,
3229+ "manual implementation of the internal `Eq::assert_receiver_is_total_eq` method" ,
3230+ @future_incompatible = FutureIncompatibleInfo {
3231+ reason: fcw!( FutureReleaseError #150000 ) ,
3232+ report_in_deps: false ,
3233+ } ;
3234+ }
3235+
3236+ declare_lint_pass ! ( EqAssertReceiverIsTotalEq => [ EQ_ASSERT_RECEIVER_IS_TOTAL_EQ_IMPL ] ) ;
3237+
3238+ impl < ' tcx > LateLintPass < ' tcx > for EqAssertReceiverIsTotalEq {
3239+ fn check_impl_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx rustc_hir:: ImplItem < ' tcx > ) {
3240+ if let ImplItemImplKind :: Trait { defaultness : _, trait_item_def_id : Ok ( trait_item_def_id) } =
3241+ item. impl_kind
3242+ && item. ident . name == sym:: assert_receiver_is_total_eq
3243+ && cx. tcx . is_diagnostic_item ( sym:: assert_receiver_is_total_eq, trait_item_def_id)
3244+ && !item. span . from_expansion ( )
3245+ {
3246+ cx. emit_span_lint (
3247+ EQ_ASSERT_RECEIVER_IS_TOTAL_EQ_IMPL ,
3248+ item. span ,
3249+ EqInternalMethodImplemented ,
3250+ ) ;
3251+ }
3252+ }
3253+ }
0 commit comments