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(Zeroable) on fieldful enums and repr(C) enums #257

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

zachs18
Copy link
Contributor

@zachs18 zachs18 commented Jul 28, 2024

Closes #230.

Allows deriving Zeroable on enums where:

  1. The enum is #[repr(Int)], #[repr(C)], or #[repr(C, Int)],
  2. There is a variant with discriminant 0,
  3. The variant with discriminant 0 is either fieldless, or all of its fields are Zeroable.

Also allows using the "perfect derive with additional bounds" from #196 for Zeroable on enums, where the fields for the "perfect derive" are from the variant with discriminant 0 (see the MyOption example on line 189 of derive/src/lib.rs).

Internal changes:

  • VariantDiscriminantIter now also gives the &'a Variant associated with the discriminant.
  • the comment on line 338 of derive/src/traits.rs kept getting mangled by cargo fmt, so I put it on its own line.
  • In derive_marker_trait_inner: let predicates = ... moved to after let fields = ..., since computing fields now requires accessing input, but predicates borrows it mutably. Does not change semantics.
  • generate_fields_are_trait and some other helper functions now take an Option<&Variant> to operate on if they otherwise don't support enums.
  • some cargo fmt
  • drive-by clarification/typo fixes (e.g. renaming discriminantor -> discriminant)

@Lokathor Lokathor requested a review from fu5ha July 30, 2024 22:16
@Lokathor Lokathor self-assigned this Aug 22, 2024
@Lokathor Lokathor added the proc-macros I don't do proc-macros, but I accepts PRs about them. label Aug 22, 2024
Copy link
Contributor

@danielhenrymantilla danielhenrymantilla left a comment

Choose a reason for hiding this comment

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

LGTM, nice! ✅

@@ -139,24 +142,23 @@ impl Derivable for Zeroable {
match ty {
Data::Struct(_) => Ok(()),
Data::Enum(DataEnum { variants, .. }) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Unrelated to this PR; but this logic does not seem to fit the name of the function (check_attributes), since it is also checking the variants and whatnot for enums. The simplest fix here would be to just change the function name accordingly, fn check_input(), fn validate[_input] or whatnot.

derive/src/traits.rs Outdated Show resolved Hide resolved
VariantDiscriminantIterator::new(variants.iter())
.map(|res| {
let (discriminant, _variant) = res?;
Ok(LitInt::new(&format!("{}", discriminant), span))
Copy link
Contributor

Choose a reason for hiding this comment

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

Unrelated to this PR, but we might as well smuggle this tiny improvement:

Suggested change
Ok(LitInt::new(&format!("{}", discriminant), span))
Ok(LitInt::new(&discriminant.to_string(), span))

Comment on lines +661 to +681
let first = &variant_discriminant_lits[0];
let rest = &variant_discriminant_lits[1..];
Copy link
Contributor

Choose a reason for hiding this comment

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

Unrelated to this PR, but it seems quite tempting to be doing the following, here:

Suggested change
let first = &variant_discriminant_lits[0];
let rest = &variant_discriminant_lits[1..];
let (first, rest) = variant_discriminant_lits.split_first().unwrap();

derive/src/traits.rs Show resolved Hide resolved
derive/src/traits.rs Outdated Show resolved Hide resolved
@@ -1215,7 +1248,7 @@ impl<'a, I: Iterator<Item = &'a Variant> + 'a> Iterator
self.last_value += 1;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Unrelated to this PR, but it seems rather important (somebody compiling proc-macros with a different choice of the overflow-checks knob may run into a panic with this logic):

Suggested change
self.last_value += 1;
self.last_value = self.last_value.wrapping_add(1);

Copy link
Contributor Author

@zachs18 zachs18 Sep 16, 2024

Choose a reason for hiding this comment

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

Hmm, in the case of the (unstable) repr128 feature, I think this could cause unsoundness with derive(CheckedBitPattern) on an #[repr(i128)] enum X { A = i64::MAX as i128, B }, so to be safe, I'll make last_value an i128 and then do the wrapping_add (since the compiler will catch any overflows at the actual discriminant type).

derive/src/traits.rs Outdated Show resolved Hide resolved
derive/src/lib.rs Outdated Show resolved Hide resolved
/// If this trait has a custom meaning for "perfect derive", this function
/// should be overridden to return `Some`.
///
/// The default is "the fields of a struct; unions and enums not supported".
Copy link
Contributor

Choose a reason for hiding this comment

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

Good and important doc 👌

  • 🤔 I wonder if we shouldn't be moving said default logic over here (by changing the output to ::syn::Result<Fields>) to ensure actual code logic and this doc comment remain in sync

@zachs18 zachs18 force-pushed the zeroable-derive-fieldful-enums branch from 653200e to b5ac207 Compare September 16, 2024 19:44
zachs18 and others added 2 commits September 16, 2024 14:46
Co-authored-by: Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com>
Co-authored-by: Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com>
Copy link
Collaborator

@fu5ha fu5ha left a comment

Choose a reason for hiding this comment

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

Nice, LGTM. I'm deferring the in depth soundness checking of the macro to @danielhenrymantilla 's review whom I trust.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proc-macros I don't do proc-macros, but I accepts PRs about them.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow deriving Zeroable for enums which are #[repr(u32, i8, etc..)]
4 participants