-
-
Notifications
You must be signed in to change notification settings - Fork 79
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
derive(Zeroable) on fieldful enums and repr(C) enums #257
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, nice! ✅
derive/src/traits.rs
Outdated
@@ -139,24 +142,23 @@ impl Derivable for Zeroable { | |||
match ty { | |||
Data::Struct(_) => Ok(()), | |||
Data::Enum(DataEnum { variants, .. }) => { |
There was a problem hiding this comment.
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 enum
s. The simplest fix here would be to just change the function name accordingly, fn check_input()
, fn validate[_input]
or whatnot.
VariantDiscriminantIterator::new(variants.iter()) | ||
.map(|res| { | ||
let (discriminant, _variant) = res?; | ||
Ok(LitInt::new(&format!("{}", discriminant), span)) |
There was a problem hiding this comment.
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:
Ok(LitInt::new(&format!("{}", discriminant), span)) | |
Ok(LitInt::new(&discriminant.to_string(), span)) |
let first = &variant_discriminant_lits[0]; | ||
let rest = &variant_discriminant_lits[1..]; |
There was a problem hiding this comment.
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:
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
Outdated
@@ -1215,7 +1248,7 @@ impl<'a, I: Iterator<Item = &'a Variant> + 'a> Iterator | |||
self.last_value += 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
overflow-checks
knob may run into a panic with this logic):
self.last_value += 1; | |
self.last_value = self.last_value.wrapping_add(1); |
There was a problem hiding this comment.
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).
/// 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". |
There was a problem hiding this comment.
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
1. the enum is repr(Int), repr(C), or repr(C, Int), 2. the enum has a variant with discriminant 0, 3. and all fields of the variant with discriminant 0 are Zeroable.
653200e
to
b5ac207
Compare
Co-authored-by: Daniel Henry-Mantilla <[email protected]>
Co-authored-by: Daniel Henry-Mantilla <[email protected]>
There was a problem hiding this 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.
Sorry about the delay, |
Closes #230.
Allows deriving
Zeroable
onenum
s where:#[repr(Int)]
,#[repr(C)]
, or#[repr(C, Int)]
,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.cargo fmt
, so I put it on its own line.derive_marker_trait_inner
:let predicates = ...
moved to afterlet fields = ...
, since computingfields
now requires accessinginput
, butpredicates
borrows it mutably. Does not change semantics.generate_fields_are_trait
and some other helper functions now take anOption<&Variant>
to operate on if they otherwise don't support enums.cargo fmt
discriminantor
->discriminant
)