1
Fork 0

Generate safe stable code for derives on empty enums

Generate `match *self {}` instead of `unsafe { core::intrinsics::unreachable() }`.

This is:

    1. safe
    2. stable

for the benefit of everyone looking at these derived impls through `cargo expand`.

Both expansions compile to the same code at all optimization levels (including `0`).
This commit is contained in:
David Tolnay 2023-07-16 14:35:16 -07:00
parent c4083faade
commit f441adc89a
No known key found for this signature in database
GPG key ID: F9BA143B95FF6D82
2 changed files with 18 additions and 13 deletions

View file

@ -1134,9 +1134,14 @@ impl<'a> MethodDef<'a> {
trait_: &TraitDef<'b>,
enum_def: &'b EnumDef,
type_ident: Ident,
selflike_args: ThinVec<P<Expr>>,
mut selflike_args: ThinVec<P<Expr>>,
nonselflike_args: &[P<Expr>],
) -> BlockOrExpr {
assert!(
!selflike_args.is_empty(),
"static methods must use `expand_static_enum_method_body`",
);
let span = trait_.span;
let variants = &enum_def.variants;
@ -1144,10 +1149,14 @@ impl<'a> MethodDef<'a> {
let unify_fieldless_variants =
self.fieldless_variants_strategy == FieldlessVariantsStrategy::Unify;
// There is no sensible code to be generated for *any* deriving on a
// zero-variant enum. So we just generate a failing expression.
// For zero-variant enum, this function body is unreachable.
// Generate `match *self {}`.
if variants.is_empty() {
return BlockOrExpr(ThinVec::new(), Some(deriving::call_unreachable(cx, span)));
selflike_args.truncate(1);
let match_arg = cx.expr_deref(span, selflike_args.pop().unwrap());
let match_arms = ThinVec::new();
let expr = cx.expr_match(span, match_arg, match_arms);
return BlockOrExpr(ThinVec::new(), Some(expr));
}
let prefixes = iter::once("__self".to_string())