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:
parent
c4083faade
commit
f441adc89a
2 changed files with 18 additions and 13 deletions
|
@ -1134,9 +1134,14 @@ impl<'a> MethodDef<'a> {
|
||||||
trait_: &TraitDef<'b>,
|
trait_: &TraitDef<'b>,
|
||||||
enum_def: &'b EnumDef,
|
enum_def: &'b EnumDef,
|
||||||
type_ident: Ident,
|
type_ident: Ident,
|
||||||
selflike_args: ThinVec<P<Expr>>,
|
mut selflike_args: ThinVec<P<Expr>>,
|
||||||
nonselflike_args: &[P<Expr>],
|
nonselflike_args: &[P<Expr>],
|
||||||
) -> BlockOrExpr {
|
) -> BlockOrExpr {
|
||||||
|
assert!(
|
||||||
|
!selflike_args.is_empty(),
|
||||||
|
"static methods must use `expand_static_enum_method_body`",
|
||||||
|
);
|
||||||
|
|
||||||
let span = trait_.span;
|
let span = trait_.span;
|
||||||
let variants = &enum_def.variants;
|
let variants = &enum_def.variants;
|
||||||
|
|
||||||
|
@ -1144,10 +1149,14 @@ impl<'a> MethodDef<'a> {
|
||||||
let unify_fieldless_variants =
|
let unify_fieldless_variants =
|
||||||
self.fieldless_variants_strategy == FieldlessVariantsStrategy::Unify;
|
self.fieldless_variants_strategy == FieldlessVariantsStrategy::Unify;
|
||||||
|
|
||||||
// There is no sensible code to be generated for *any* deriving on a
|
// For zero-variant enum, this function body is unreachable.
|
||||||
// zero-variant enum. So we just generate a failing expression.
|
// Generate `match *self {}`.
|
||||||
if variants.is_empty() {
|
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())
|
let prefixes = iter::once("__self".to_string())
|
||||||
|
|
|
@ -798,14 +798,14 @@ impl ::core::marker::Copy for Enum0 { }
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl ::core::fmt::Debug for Enum0 {
|
impl ::core::fmt::Debug for Enum0 {
|
||||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||||
unsafe { ::core::intrinsics::unreachable() }
|
match *self {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl ::core::hash::Hash for Enum0 {
|
impl ::core::hash::Hash for Enum0 {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
|
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
|
||||||
unsafe { ::core::intrinsics::unreachable() }
|
match *self {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
|
@ -813,9 +813,7 @@ impl ::core::marker::StructuralPartialEq for Enum0 { }
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl ::core::cmp::PartialEq for Enum0 {
|
impl ::core::cmp::PartialEq for Enum0 {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eq(&self, other: &Enum0) -> bool {
|
fn eq(&self, other: &Enum0) -> bool { match *self {} }
|
||||||
unsafe { ::core::intrinsics::unreachable() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl ::core::marker::StructuralEq for Enum0 { }
|
impl ::core::marker::StructuralEq for Enum0 { }
|
||||||
|
@ -831,15 +829,13 @@ impl ::core::cmp::PartialOrd for Enum0 {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn partial_cmp(&self, other: &Enum0)
|
fn partial_cmp(&self, other: &Enum0)
|
||||||
-> ::core::option::Option<::core::cmp::Ordering> {
|
-> ::core::option::Option<::core::cmp::Ordering> {
|
||||||
unsafe { ::core::intrinsics::unreachable() }
|
match *self {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl ::core::cmp::Ord for Enum0 {
|
impl ::core::cmp::Ord for Enum0 {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn cmp(&self, other: &Enum0) -> ::core::cmp::Ordering {
|
fn cmp(&self, other: &Enum0) -> ::core::cmp::Ordering { match *self {} }
|
||||||
unsafe { ::core::intrinsics::unreachable() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A single-variant enum.
|
// A single-variant enum.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue