derive(Zeroable) on fieldful enums and repr(C) enums#257
Conversation
danielhenrymantilla
left a comment
There was a problem hiding this comment.
LGTM, nice! ✅
| @@ -139,24 +142,23 @@ impl Derivable for Zeroable { | |||
| match ty { | |||
| Data::Struct(_) => Ok(()), | |||
| Data::Enum(DataEnum { variants, .. }) => { | |||
There was a problem hiding this comment.
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.
| VariantDiscriminantIterator::new(variants.iter()) | ||
| .map(|res| { | ||
| let (discriminant, _variant) = res?; | ||
| Ok(LitInt::new(&format!("{}", discriminant), span)) |
There was a problem hiding this comment.
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.
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(); |
| @@ -1215,7 +1248,7 @@ impl<'a, I: Iterator<Item = &'a Variant> + 'a> Iterator | |||
| self.last_value += 1; | |||
There was a problem hiding this comment.
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.
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.
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 <daniel.henry.mantilla@gmail.com>
Co-authored-by: Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com>
fu5ha
left a comment
There was a problem hiding this comment.
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
Zeroableonenums 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
MyOptionexample on line 189 of derive/src/lib.rs).Internal changes:
VariantDiscriminantIternow also gives the&'a Variantassociated with the discriminant.cargo fmt, so I put it on its own line.derive_marker_trait_inner:let predicates = ...moved to afterlet fields = ..., since computingfieldsnow requires accessinginput, butpredicatesborrows it mutably. Does not change semantics.generate_fields_are_traitand some other helper functions now take anOption<&Variant>to operate on if they otherwise don't support enums.cargo fmtdiscriminantor->discriminant)