Skip to content

Commit 93b9812

Browse files
authored
Rollup merge of #113770 - dtolnay:derivevoid, r=compiler-errors,nnethercote
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`).](https://rust.godbolt.org/z/P79joGMh3)
2 parents eca9c01 + 56633b3 commit 93b9812

File tree

2 files changed

+19
-13
lines changed

2 files changed

+19
-13
lines changed

compiler/rustc_builtin_macros/src/deriving/generic/mod.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -1134,20 +1134,30 @@ impl<'a> MethodDef<'a> {
11341134
trait_: &TraitDef<'b>,
11351135
enum_def: &'b EnumDef,
11361136
type_ident: Ident,
1137-
selflike_args: ThinVec<P<Expr>>,
1137+
mut selflike_args: ThinVec<P<Expr>>,
11381138
nonselflike_args: &[P<Expr>],
11391139
) -> BlockOrExpr {
1140+
assert!(
1141+
!selflike_args.is_empty(),
1142+
"static methods must use `expand_static_enum_method_body`",
1143+
);
1144+
11401145
let span = trait_.span;
11411146
let variants = &enum_def.variants;
11421147

11431148
// Traits that unify fieldless variants always use the tag(s).
11441149
let unify_fieldless_variants =
11451150
self.fieldless_variants_strategy == FieldlessVariantsStrategy::Unify;
11461151

1147-
// There is no sensible code to be generated for *any* deriving on a
1148-
// zero-variant enum. So we just generate a failing expression.
1152+
// For zero-variant enum, this function body is unreachable. Generate
1153+
// `match *self {}`. This produces machine code identical to `unsafe {
1154+
// core::intrinsics::unreachable() }` while being safe and stable.
11491155
if variants.is_empty() {
1150-
return BlockOrExpr(ThinVec::new(), Some(deriving::call_unreachable(cx, span)));
1156+
selflike_args.truncate(1);
1157+
let match_arg = cx.expr_deref(span, selflike_args.pop().unwrap());
1158+
let match_arms = ThinVec::new();
1159+
let expr = cx.expr_match(span, match_arg, match_arms);
1160+
return BlockOrExpr(ThinVec::new(), Some(expr));
11511161
}
11521162

11531163
let prefixes = iter::once("__self".to_string())

tests/ui/deriving/deriving-all-codegen.stdout

+5-9
Original file line numberDiff line numberDiff line change
@@ -798,24 +798,22 @@ impl ::core::marker::Copy for Enum0 { }
798798
#[automatically_derived]
799799
impl ::core::fmt::Debug for Enum0 {
800800
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
801-
unsafe { ::core::intrinsics::unreachable() }
801+
match *self {}
802802
}
803803
}
804804
#[automatically_derived]
805805
impl ::core::hash::Hash for Enum0 {
806806
#[inline]
807807
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
808-
unsafe { ::core::intrinsics::unreachable() }
808+
match *self {}
809809
}
810810
}
811811
#[automatically_derived]
812812
impl ::core::marker::StructuralPartialEq for Enum0 { }
813813
#[automatically_derived]
814814
impl ::core::cmp::PartialEq for Enum0 {
815815
#[inline]
816-
fn eq(&self, other: &Enum0) -> bool {
817-
unsafe { ::core::intrinsics::unreachable() }
818-
}
816+
fn eq(&self, other: &Enum0) -> bool { match *self {} }
819817
}
820818
#[automatically_derived]
821819
impl ::core::marker::StructuralEq for Enum0 { }
@@ -831,15 +829,13 @@ impl ::core::cmp::PartialOrd for Enum0 {
831829
#[inline]
832830
fn partial_cmp(&self, other: &Enum0)
833831
-> ::core::option::Option<::core::cmp::Ordering> {
834-
unsafe { ::core::intrinsics::unreachable() }
832+
match *self {}
835833
}
836834
}
837835
#[automatically_derived]
838836
impl ::core::cmp::Ord for Enum0 {
839837
#[inline]
840-
fn cmp(&self, other: &Enum0) -> ::core::cmp::Ordering {
841-
unsafe { ::core::intrinsics::unreachable() }
842-
}
838+
fn cmp(&self, other: &Enum0) -> ::core::cmp::Ordering { match *self {} }
843839
}
844840

845841
// A single-variant enum.

0 commit comments

Comments
 (0)