diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2023-07-17 12:58:54 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-07-17 12:58:54 +0200 |
| commit | 93b9812be840ec218bf499dcc5c6f81f20ea3002 (patch) | |
| tree | 99f59b3ad68e0fcc2e60459b7def45ba2d92c656 | |
| parent | eca9c0101c98df239e02c34f7b802cf775b86d08 (diff) | |
| parent | 56633b3f51967f544c988dcabbcd1b99f4cc3558 (diff) | |
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)
| -rw-r--r-- | compiler/rustc_builtin_macros/src/deriving/generic/mod.rs | 18 | ||||
| -rw-r--r-- | tests/ui/deriving/deriving-all-codegen.stdout | 14 |
2 files changed, 19 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..9865b6a72ee 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,15 @@ 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 {}`. This produces machine code identical to `unsafe { + // core::intrinsics::unreachable() }` while being safe and stable. 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. |
