Uh oh!
There was an error while loading. Please reload this page.
Change derive macro for Eq to not impl Eq trait fn - #153125
Conversation
rustbot
commented
Feb 26, 2026
Changes to the code generated for builtin derived traits. cc @nnethercote |
This comment has been minimized.
This comment has been minimized.
Uh oh!
There was an error while loading. Please reload this page.
theemathas
commented
Feb 26, 2026
A test case that seems like might break with this: traitTrait<T>{}#[derive(PartialEq,Eq)]structThing<T:Trait<Self>>(T); |
theemathas
commented
Feb 26, 2026
A less exotic test case: #[derive(PartialEq,Eq)]structThing(Option<Box<Self>>); |
Kivooeo
commented
Feb 26, 2026
Nick, I would reassign to you (feel free to reroll) since @cyrgani is a triage member and can't approve compiler changes r? nnethercote |
Gah, because we're now generating a const item instead of a trait impl block, we'd need to rewrite the A better solution now would be to emit the following: impl<...> Type<...> {constfnassert_fields_are_eq(){let _:::core::cmp::AssertParamIsEq<Option<Box<Self>>>;}}This would side-step the issue of rewriting |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Uh oh!
There was an error while loading. Please reload this page.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
KiChjang
commented
Feb 28, 2026
Looks like CI is passing now, r? @nnethercote |
rustbot
commented
Feb 28, 2026
Requested reviewer is already assigned to this pull request. Please choose another assignee. |
cyrgani
commented
Feb 28, 2026
You should be able to delete the |
cyrgani
commented
Feb 28, 2026
Could you also add a test that something like fnmain(){X::assert_fields_are_eq();}#[derive(PartialEq,Eq)]structX(u8);will not compile? |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
This is now completely different to the original idea of using a const. I'm no lang expert, but injecting X::assert_fields_are_eq doesn't seem acceptable to me.
Beyond that, I've only skimmed the PR so far. I think the 8 commits should be squashed down to 1 or 2. I'm also surprised at how much extra code is required in eq.rs to generate a slight variation on what is currently generated.
KiChjang
commented
Mar 1, 2026
This probably would still compile, since what I essentially did was move the trait method to be under an inherent impl instead, which is probably why it isn't desirable. Given so, I'd probably need to revert to the original idea of using a const item block, however the const fn would still have to stay the same because I'd still need to somehow bring all lifetime/type parameters into scope, and if we don't use an impl, then a fn is the minimal vehicle to do so. |
nnethercote
commented
Mar 1, 2026
That's right. Currently we have a hidden method in |
rust-timer
commented
Mar 2, 2026
Insufficient permissions to issue commands to rust-timer. |
KiChjang
commented
Mar 2, 2026
This seems to emit quite a lot of boilerplate for the purpose of making sure that Would appreciate some help in putting this on the timer queue though as I don't have sufficient permissions. |
| impl ::core::cmp::Eq for PackedPoint { | ||
| #[inline] | ||
| impl ::core::cmp::Eq for PackedPoint { } | ||
| const { |
There was a problem hiding this comment.
This isn't even valid syntax, it should be const _: () = {.
There was a problem hiding this comment.
This is the code that gets generated when I tell the compiler to emit a ast::ItemKind::ConstBlock:
rust/compiler/rustc_ast/src/ast.rs
Lines 3955 to 3959 in 8d50bcc
There was a problem hiding this comment.
Weird. Maybe a pretty printing issue? Would be good to understand what's happening here.
There was a problem hiding this comment.
Hmm, so it's apparently a feature gated behind const_block_items in #149226. I'm also curious as to why it's necessary to generate a new ItemKind specifically for it when it's equivalent to const _: () = const { ... } in all cases and purposes. Will change to use the const item instead.
This comment has been minimized.
This comment has been minimized.
c694584 to
602529dCompare602529d to
c70ca54Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
| mut_visit::walk_ty(self, ty); | ||
| } | ||
| } | ||
| fn visit_expr(&mut self, expr: &mut ast::Expr) { |
There was a problem hiding this comment.
Please put blank lines between the methods, here and elsewhere.
| use crate::deriving::generic::*; | ||
| use crate::deriving::path_std; | ||
| struct ReplaceSelfTyVisitor(Box<ast::Ty>); |
There was a problem hiding this comment.
Blank line after the struct, and likewise below.
There was a problem hiding this comment.
Also, the three visitors need a brief comment explaining what they are doing and why.
| span, | ||
| }; | ||
| cx.item( |
There was a problem hiding this comment.
A brief example of the kind of code being generated would be helpful here.
| #[coverage(off)] | ||
| fn assert_fields_are_eq(&self) { | ||
| #[inline] | ||
| const fn assert_fields_are_eq(_: *const Point) { |
There was a problem hiding this comment.
I assume the parameter to assert_fields_are_eq is necessary in the generic case to make the trait bounds work? But could the parameter be avoided for non-generic functions like this one?
There was a problem hiding this comment.
Also, why is the parameter (when present) *const T? Could it just be T?
There was a problem hiding this comment.
Also, why is the parameter (when present)
*const T? Could it just beT?
Probably to work with ?Sized types?
There was a problem hiding this comment.
Another option to make it work properly with Self, while not doing an inherent method:
Add an extra trait with the method on it instead.
// `#[doc(hidden)]` trait (and unstable if we can?)impl::core::cmp::EqHelperTraitfor $ty {#[inline]fnassert_fields_are_eq(){let _:::core::cmp::AssertParamIsEq<$param1>;let _:::core::cmp::AssertParamIsEq<$param2>;// ...}}| const LEN: usize = 10; | ||
| } | ||
| // An empty enum. |
There was a problem hiding this comment.
Please add a test case like this:
macro_rules! get_self {() => {Self};}#[derive(Clone,Debug,PartialEq,Eq,PartialOrd,Ord,Hash,Default)]structSelfFromMacro{this:Option<Box<get_self!()>>}(I'm commenting this specifically because I think that any solution that matches on the token Self isn't gonna work).
nnethercote
commented
Mar 9, 2026
The whole point of this PR is to eliminate a hidden name. Let's not introduce a new hidden name, even if it is unstable. |
madsmtm
commented
Mar 10, 2026
Idk., I think there's a difference between a hidden name on DetailsIdeally we'd be able to do this: structFoo;implFoo{const _:() = {// reference `Self` here.};}But that's probably a bit far off, see rust-lang/rfcs#3527. |
This was what I had in an earlier revision, but it was not desirable as mentioned by @nnethercote since it still introduces a new name. I am thinking however that maybe we could instead make all assert bindings be associated const bindings instead? E.g. structFoo(u32);implFoo{const _:::core::cmp::AssertParamIsEq<u32> = ::core::cmp::AssertParamIsEq{_field:PhantomData};} |
nnethercote
commented
Mar 12, 2026
Sounds promising! It's anonymous, and uses (Thanks for your patience on this, BTW. It has turned out more complicated than it first appeared.) |
theemathas
commented
Mar 12, 2026
@KiChjang@nnethercote That won't work. It seems like associated consts must have a proper name: structFoo;implFoo{const _:i32 = 1;} |
KiChjang
commented
Mar 12, 2026
Ah crud, I experimented around and consulted the Rust lang reference a couple of times, and it looks like at this point in time, Rust does not allow ANY associated items in an impl block to be anonymous (i.e. underscore). This means we can't avoid introducing a new name if we go the impl block route -- we MUST use a const item block instead, but that then makes the I now wonder if there's a way for us to tell the compiler to relax some restrictions around naming for associated items in impl blocks if the code in question is generated from an compiler builtin macro... But if we are going down this route, I'm also wondering whether it is ok to special case this for the aristocratic and special builtin derive macros? Maybe the better way is to instead open an RFC allowing for anonymous associated items? |
madsmtm
commented
Mar 12, 2026
One exists: rust-lang/rfcs#3527. |
☔ The latest upstream changes (presumably #155796) made this pull request unmergeable. Please resolve the merge conflicts. |
KiChjang
commented
Jul 15, 2026
Now waiting for #158944 to resolve so that we can make use of the language feature for this task. |
View all comments
Fixes#152504.
r? @cyrgani