about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Tolnay <dtolnay@gmail.com>2023-07-16 14:35:16 -0700
committerDavid Tolnay <dtolnay@gmail.com>2023-07-16 15:02:08 -0700
commitf441adc89a880df995ed95ca1402cfe8939d273b (patch)
treea2574fba42d26f995c2fb465ca0ef1732673d7b5
parentc4083faade32b16feb471ef082ce0b1e3fe94262 (diff)
downloadrust-f441adc89a880df995ed95ca1402cfe8939d273b.tar.gz
rust-f441adc89a880df995ed95ca1402cfe8939d273b.zip
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`).
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs17
-rw-r--r--tests/ui/deriving/deriving-all-codegen.stdout14
2 files changed, 18 insertions, 13 deletions
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 4ba09335cb7..0f51b26de09 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -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())
diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout
index d6a2c80cc06..6bfc859bfe8 100644
--- a/tests/ui/deriving/deriving-all-codegen.stdout
+++ b/tests/ui/deriving/deriving-all-codegen.stdout
@@ -798,14 +798,14 @@ impl ::core::marker::Copy for Enum0 { }
 #[automatically_derived]
 impl ::core::fmt::Debug for Enum0 {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
-        unsafe { ::core::intrinsics::unreachable() }
+        match *self {}
     }
 }
 #[automatically_derived]
 impl ::core::hash::Hash for Enum0 {
     #[inline]
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
-        unsafe { ::core::intrinsics::unreachable() }
+        match *self {}
     }
 }
 #[automatically_derived]
@@ -813,9 +813,7 @@ impl ::core::marker::StructuralPartialEq for Enum0 { }
 #[automatically_derived]
 impl ::core::cmp::PartialEq for Enum0 {
     #[inline]
-    fn eq(&self, other: &Enum0) -> bool {
-        unsafe { ::core::intrinsics::unreachable() }
-    }
+    fn eq(&self, other: &Enum0) -> bool { match *self {} }
 }
 #[automatically_derived]
 impl ::core::marker::StructuralEq for Enum0 { }
@@ -831,15 +829,13 @@ impl ::core::cmp::PartialOrd for Enum0 {
     #[inline]
     fn partial_cmp(&self, other: &Enum0)
         -> ::core::option::Option<::core::cmp::Ordering> {
-        unsafe { ::core::intrinsics::unreachable() }
+        match *self {}
     }
 }
 #[automatically_derived]
 impl ::core::cmp::Ord for Enum0 {
     #[inline]
-    fn cmp(&self, other: &Enum0) -> ::core::cmp::Ordering {
-        unsafe { ::core::intrinsics::unreachable() }
-    }
+    fn cmp(&self, other: &Enum0) -> ::core::cmp::Ordering { match *self {} }
 }
 
 // A single-variant enum.