Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Derive partialeq "manually" when possible #1012

Merged
merged 4 commits into from
Oct 2, 2017

Conversation

pepyakin
Copy link
Contributor

Fixes #879

r? @fitzgen

@highfive
Copy link

warning Warning warning

  • These commits modify unsafe code. Please review it carefully!

});
} else {
for (i, base) in comp_info.base_members().iter().enumerate() {
// TODO: Move base field name generation into either in IR or in context.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fitzgen There is a similar thing as with anonymous field names.
It's kinda works but ugly. What is the best possible way there?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a field_name member to Base, compute it upon construction of the Base, and then use that name both here and in codegen.

In fact, that could even be its own little PR, and we could land it independently of the rest of this stuff.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact, that could even be its own little PR, and we could land it independently of the rest of this stuff.

Done #1014 !

src/lib.rs Outdated
@@ -247,10 +255,6 @@ impl Builder {
output_vector.push("--no-derive-debug".into());
}

if !self.options.impl_debug {
Copy link
Contributor Author

@pepyakin pepyakin Sep 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose this was a bug...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be if self.options.impl_debug { ... }; we still want to add it to the output when set. Care to do this in a new PR?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Err, I see you did that in another place. Want to submit that as a new PR or at least make it its own standalone commit?

Copy link
Contributor Author

@pepyakin pepyakin Sep 22, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I thought I would rebase & squash, but now I see that this PR is becoming too big.

// only for arrays greater than 32.
// TODO: But is there can be only arrays?
// Why inside of the can_trivially_derive_partialeq_or_partialord is map_or(false) ?
return self.insert(id, Reason::ArrayTooLarge);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l.opaque().can_trivially_derive_partialeq_or_partialord() contains a check if the array is large enough or not.

https://github.com/rust-lang-nursery/rust-bindgen/blob/30d6e0417a691da4f4959c8083328241fc02d1fd/src/ir/layout.rs#L142-L146

but it feels ugly, because it depends on the implementation of l.opaque().can_trivially_derive_partialeq_or_partialord(). Do you see a better way there?

As an aside:
Now, I realize that it is generally ok to derive PartialEq for the opaque, but what it means to derive PartialOrd for the opaque? Maybe we should split those...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could define enum CanDerive { Yes, No(Reason) } and have CanTriviallyDerive... return No(ArrayTooLarge) so that we aren't relying on implicit information here.

Now, I realize that it is generally ok to derive PartialEq for the opaque, but what it means to derive PartialOrd for the opaque? Maybe we should split those...

Want to file a new issue to discuss this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Want to file a new issue to discuss this?

Done #1013 !

@@ -143,8 +146,9 @@ impl<'ctx> MonotoneFramework for CannotDerivePartialEqOrPartialOrd<'ctx> {
trace!(" we can trivially derive PartialEq or PartialOrd for the layout");
ConstrainResult::Same
} else {
// TODO: opaque can depend on arrays size at the moment
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let name = match fd.name() {
Some(name) => name,
None => {
// TODO: Bitfield stuff
Copy link
Contributor Author

@pepyakin pepyakin Sep 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fitzgen Is it OK to just warn and don't generate PartialEq until we rule out the situation around anonymous field names?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's fine.

bors-servo pushed a commit that referenced this pull request Sep 22, 2017
@bors-servo
Copy link

☔ The latest upstream changes (presumably #1016) made this pull request unmergeable. Please resolve the merge conflicts.

@pepyakin
Copy link
Contributor Author

Hm, not sure what is going on.

These tests (cd tests/expectations && cargo test) passes locally (well, almost, except those objc* ones)

The error

error[E0277]: the trait bound `[i32; 33]: std::clone::Clone` is not satisfied
  --> tests/derive-partialeq-template-inst.rs:10:5
   |
10 |     pub large: [::std::os::raw::c_int; 33usize],
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `[i32; 33]`
   |
   = help: the following implementations were found:
             <[T; 24] as std::clone::Clone>
             <[T; 6] as std::clone::Clone>
             <[T; 16] as std::clone::Clone>
             <[T; 0] as std::clone::Clone>
           and 29 others
   = note: required by `std::clone::Clone::clone`

Seems like this struct doesn't derive Copy. Have no idea why is that.

@pepyakin
Copy link
Contributor Author

pepyakin commented Sep 24, 2017

I managed to reproduce this on my machine. This happens only on stable rustc 1.20 and not on beta/nightly because of all_the_clones.

@bors-servo
Copy link

☔ The latest upstream changes (presumably #1005) made this pull request unmergeable. Please resolve the merge conflicts.

@pepyakin pepyakin force-pushed the derive-partialeq-manually branch 3 times, most recently from a095153 to 4932c6f Compare October 2, 2017 11:10
Copy link
Member

@fitzgen fitzgen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Just a couple nitpicks below.

Thanks @pepyakin !

} else if comp_info.kind() == CompKind::Union {
tokens.push(quote! {
&self.bindgen_union_field[..] == &other.bindgen_union_field[..]
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will only work if we aren't emitting Rust unions, so it should check ctx.options().rust_features().untagged_union()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we would have CannotDeriveReason::Other here for Rust unions so this logic is actually OK as-is. That's pretty subtle, so we should definitely assert!(!ctx.options().rust_features().untagged_union()) in this branch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense!

quote_equals(name_ident)
} else {
quote! {
&self. #name_ident [..] == &other. #name_ident [..]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, we don't even need a loop ;)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was inspired by rustc itself (Just looked how it handles cases below 32 😄 )

Some(CannotDeriveReason::Other) => 2,
}
}
rank(from) <= rank(to)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like this whole rank thing could be an implementation of PartialOrd for CannotDeriveReason and then we could do from <= to. Am I missing anything?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took that way because I didn't want to make public the fact that they are can be ordered.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And by they I mean Option<CannotDeriveReason> :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think, @fitzgen , is it makes sense?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, sounds good to me

trace!("constrain: {:?}", id);

if Some(CannotDeriveReason::Other)
== self.cannot_derive_partialeq_or_partialord.get(&id).cloned()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use an if-let here?

if let Some(CannotDeriveReason::Other) = ... 

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep

}
}

fn constrain_join(&mut self, item: &Item) -> Option<CannotDeriveReason> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding this!

// bindgen-flags: --with-derive-partialeq --impl-partialeq

// Deriving PartialEq for rust unions is not supported.
union ShouldNotDerivePartialEq {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we make this comment use /// or /** ... */ style, then it will appear in the expectations too, which is sometimes useful for checking that the trait you expect to derive or not is as expected.

// bindgen-flags: --rust-target 1.0 --with-derive-partialeq --impl-partialeq

// This should manually derive PartialEq.
union ShouldDerivePartialEq {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

@pepyakin pepyakin force-pushed the derive-partialeq-manually branch from 4932c6f to b7bd43a Compare October 2, 2017 20:57
Copy link
Member

@fitzgen fitzgen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 thanks!

@fitzgen fitzgen changed the title Derive partialeq "manually" when possible [WIP] Derive partialeq "manually" when possible Oct 2, 2017
@fitzgen
Copy link
Member

fitzgen commented Oct 2, 2017

@bors-servo r+

@bors-servo
Copy link

📌 Commit b7bd43a has been approved by fitzgen

@bors-servo
Copy link

⌛ Testing commit b7bd43a with merge 48ca92b...

bors-servo pushed a commit that referenced this pull request Oct 2, 2017
Derive partialeq "manually" when possible

Fixes #879

r? @fitzgen
@bors-servo
Copy link

💔 Test failed - status-travis

@bors-servo
Copy link

☔ The latest upstream changes (presumably #1050) made this pull request unmergeable. Please resolve the merge conflicts.

@bors-servo
Copy link

☀️ Test successful - status-travis
Approved by: fitzgen
Pushing 48ca92b to master...

@bors-servo
Copy link

👀 Test was successful, but fast-forwarding failed: 422 Update is not a fast forward

Remove derive-partialeq-template-inst test.

Add comments.

Don't implement PartialEq for incomplete arrays

Handle opaque bases and template instantiations

Extract constrain_type.

Extract `is whitelisted?` check

Add failing partialeq-anonfield

join for comps

Fix: return insert if not whitelisted

Delegate TypeRefs and alias to constrain_join.

Delegate Template instantiations to constrain_join

Add derive-partialeq-pointer.hpp test

Update comment.

Fix layout alignment larger that array limit

Add missing test for derive-partialeq-anonfield.rs

Clean

Clean

Fix typo in opaque-template-inst-member test

Remove redudant stmt

Add comment on can_supersede.

Format impl_partialeq and leave a comment

Extract requires_storage into it's own function.

Clean
@pepyakin
Copy link
Contributor Author

pepyakin commented Oct 2, 2017

I rebased the PR @fitzgen !

@fitzgen
Copy link
Member

fitzgen commented Oct 2, 2017

@bors-servo r+

@bors-servo
Copy link

📌 Commit 617c55b has been approved by fitzgen

@bors-servo
Copy link

⌛ Testing commit 617c55b with merge 4e74c39...

bors-servo pushed a commit that referenced this pull request Oct 2, 2017
Derive partialeq "manually" when possible

Fixes #879

r? @fitzgen
@bors-servo
Copy link

☀️ Test successful - status-travis
Approved by: fitzgen
Pushing 4e74c39 to master...

@bors-servo bors-servo merged commit 617c55b into rust-lang:master Oct 2, 2017
@pepyakin pepyakin deleted the derive-partialeq-manually branch October 3, 2017 05:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants