diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index ec3006898f33b..e7d242ab70364 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -1042,21 +1042,31 @@ impl<'a> MethodDef<'a> { /// variants where all of the variants match, and one catch-all for /// when one does not match. + /// As an optimization we generate code which checks whether all variants + /// match first which makes llvm see that C-like enums can be compiled into + /// a simple equality check (for PartialEq). + /// The catch-all handler is provided access the variant index values - /// for each of the self-args, carried in precomputed variables. (Nota - /// bene: the variant index values are not necessarily the - /// discriminant values. See issue #15523.) + /// for each of the self-args, carried in precomputed variables. /// ```{.text} - /// match (this, that, ...) { - /// (Variant1, Variant1, Variant1) => ... // delegate Matching on Variant1 - /// (Variant2, Variant2, Variant2) => ... // delegate Matching on Variant2 - /// ... - /// _ => { - /// let __this_vi = match this { Variant1 => 0, Variant2 => 1, ... }; - /// let __that_vi = match that { Variant1 => 0, Variant2 => 1, ... }; + /// let __self0_vi = unsafe { + /// std::intrinsics::discriminant_value(&self) } as i32; + /// let __self1_vi = unsafe { + /// std::intrinsics::discriminant_value(&__arg1) } as i32; + /// let __self2_vi = unsafe { + /// std::intrinsics::discriminant_value(&__arg2) } as i32; + /// + /// if __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... { + /// match (...) { + /// (Variant1, Variant1, ...) => Body1 + /// (Variant2, Variant2, ...) => Body2, + /// ... + /// _ => ::core::intrinsics::unreachable() + /// } + /// } + /// else { /// ... // catch-all remainder can inspect above variant index values. - /// } /// } /// ``` fn build_enum_match_tuple<'b>( @@ -1187,7 +1197,6 @@ impl<'a> MethodDef<'a> { cx.arm(sp, vec![single_pat], arm_expr) }).collect(); - // We will usually need the catch-all after matching the // tuples `(VariantK, VariantK, ...)` for each VariantK of the // enum. But: @@ -1223,9 +1232,14 @@ impl<'a> MethodDef<'a> { // ``` let mut index_let_stmts: Vec
> = Vec::new();
+ //We also build an expression which checks whether all discriminants are equal
+ // discriminant_test = __self0_vi == __self1_vi && __self0_vi == __self2_vi && ...
+ let mut discriminant_test = cx.expr_bool(sp, true);
+
let target_type_name =
find_repr_type_name(&cx.parse_sess.span_diagnostic, type_attrs);
+ let mut first_ident = None;
for (&ident, self_arg) in vi_idents.iter().zip(&self_args) {
let path = vec![cx.ident_of_std("core"),
cx.ident_of("intrinsics"),
@@ -1243,32 +1257,64 @@ impl<'a> MethodDef<'a> {
let variant_disr = cx.expr_cast(sp, variant_value, target_ty);
let let_stmt = cx.stmt_let(sp, false, ident, variant_disr);
index_let_stmts.push(let_stmt);
+
+ match first_ident {
+ Some(first) => {
+ let first_expr = cx.expr_ident(sp, first);
+ let id = cx.expr_ident(sp, ident);
+ let test = cx.expr_binary(sp, ast::BiEq, first_expr, id);
+ discriminant_test = cx.expr_binary(sp, ast::BiAnd, discriminant_test, test)
+ }
+ None => {
+ first_ident = Some(ident);
+ }
+ }
}
let arm_expr = self.call_substructure_method(
cx, trait_, type_ident, &self_args[..], nonself_args,
&catch_all_substructure);
- // Builds the expression:
- // {
- // let __self0_vi = ...;
- // let __self1_vi = ...;
- // ...
- //