@@ -1048,15 +1048,23 @@ impl<'a> MethodDef<'a> {
10481048 /// discriminant values. See issue #15523.)
10491049
10501050 /// ```{.text}
1051- /// match (this, that, ...) {
1052- /// (Variant1, Variant1, Variant1) => ... // delegate Matching on Variant1
1053- /// (Variant2, Variant2, Variant2) => ... // delegate Matching on Variant2
1054- /// ...
1055- /// _ => {
1056- /// let __this_vi = match this { Variant1 => 0, Variant2 => 1, ... };
1057- /// let __that_vi = match that { Variant1 => 0, Variant2 => 1, ... };
1051+ /// let __self0_vi = unsafe {
1052+ /// std::intrinsics::discriminant_value(&self) } as i32;
1053+ /// let __self1_vi = unsafe {
1054+ /// std::intrinsics::discriminant_value(&__arg1) } as i32;
1055+ /// let __self2_vi = unsafe {
1056+ /// std::intrinsics::discriminant_value(&__arg2) } as i32;
1057+ ///
1058+ /// if __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... {
1059+ /// match (...) {
1060+ /// (Variant1, Variant1, ...) => Body1
1061+ /// (Variant2, Variant2, ...) => Body2,
1062+ /// ...
1063+ /// _ => ::core::intrinsics::unreachable()
1064+ /// }
1065+ /// }
1066+ /// else {
10581067 /// ... // catch-all remainder can inspect above variant index values.
1059- /// }
10601068 /// }
10611069 /// ```
10621070 fn build_enum_match_tuple < ' b > (
@@ -1187,7 +1195,6 @@ impl<'a> MethodDef<'a> {
11871195
11881196 cx. arm ( sp, vec ! [ single_pat] , arm_expr)
11891197 } ) . collect ( ) ;
1190-
11911198 // We will usually need the catch-all after matching the
11921199 // tuples `(VariantK, VariantK, ...)` for each VariantK of the
11931200 // enum. But:
@@ -1223,9 +1230,14 @@ impl<'a> MethodDef<'a> {
12231230 // ```
12241231 let mut index_let_stmts: Vec < P < ast:: Stmt > > = Vec :: new ( ) ;
12251232
1233+ //We also build an expression which checks whether all discriminants are equal
1234+ // discriminant_test = __self0_vi == __self1_vi && __self0_vi == __self2_vi && ...
1235+ let mut discriminant_test = cx. expr_bool ( sp, true ) ;
1236+
12261237 let target_type_name =
12271238 find_repr_type_name ( & cx. parse_sess . span_diagnostic , type_attrs) ;
12281239
1240+ let mut first_ident = None ;
12291241 for ( & ident, self_arg) in vi_idents. iter ( ) . zip ( & self_args) {
12301242 let path = vec ! [ cx. ident_of_std( "core" ) ,
12311243 cx. ident_of( "intrinsics" ) ,
@@ -1243,32 +1255,64 @@ impl<'a> MethodDef<'a> {
12431255 let variant_disr = cx. expr_cast ( sp, variant_value, target_ty) ;
12441256 let let_stmt = cx. stmt_let ( sp, false , ident, variant_disr) ;
12451257 index_let_stmts. push ( let_stmt) ;
1258+
1259+ match first_ident {
1260+ Some ( first) => {
1261+ let first_expr = cx. expr_ident ( sp, first) ;
1262+ let id = cx. expr_ident ( sp, ident) ;
1263+ let test = cx. expr_binary ( sp, ast:: BiEq , first_expr, id) ;
1264+ discriminant_test = cx. expr_binary ( sp, ast:: BiAnd , discriminant_test, test)
1265+ }
1266+ None => {
1267+ first_ident = Some ( ident) ;
1268+ }
1269+ }
12461270 }
12471271
12481272 let arm_expr = self . call_substructure_method (
12491273 cx, trait_, type_ident, & self_args[ ..] , nonself_args,
12501274 & catch_all_substructure) ;
12511275
1252- // Builds the expression:
1253- // {
1254- // let __self0_vi = ...;
1255- // let __self1_vi = ...;
1256- // ...
1257- // <delegated expression referring to __self0_vi, et al.>
1258- // }
1259- let arm_expr = cx. expr_block (
1260- cx. block_all ( sp, index_let_stmts, Some ( arm_expr) ) ) ;
1261-
1262- // Builds arm:
1263- // _ => { let __self0_vi = ...;
1264- // let __self1_vi = ...;
1265- // ...
1266- // <delegated expression as above> }
1267- let catch_all_match_arm =
1268- cx. arm ( sp, vec ! [ cx. pat_wild( sp) ] , arm_expr) ;
1269-
1270- match_arms. push ( catch_all_match_arm) ;
1271-
1276+ //Since we know that all the arguments will match if we reach the match expression we
1277+ //add the unreachable intrinsics as the result of the catch all which should help llvm
1278+ //in optimizing it
1279+ let path = vec ! [ cx. ident_of_std( "core" ) ,
1280+ cx. ident_of( "intrinsics" ) ,
1281+ cx. ident_of( "unreachable" ) ] ;
1282+ let call = cx. expr_call_global (
1283+ sp, path, vec ! [ ] ) ;
1284+ let unreachable = cx. expr_block ( P ( ast:: Block {
1285+ stmts : vec ! [ ] ,
1286+ expr : Some ( call) ,
1287+ id : ast:: DUMMY_NODE_ID ,
1288+ rules : ast:: UnsafeBlock ( ast:: CompilerGenerated ) ,
1289+ span : sp } ) ) ;
1290+ match_arms. push ( cx. arm ( sp, vec ! [ cx. pat_wild( sp) ] , unreachable) ) ;
1291+
1292+ // Final wrinkle: the self_args are expressions that deref
1293+ // down to desired l-values, but we cannot actually deref
1294+ // them when they are fed as r-values into a tuple
1295+ // expression; here add a layer of borrowing, turning
1296+ // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
1297+ let borrowed_self_args = self_args. move_map ( |self_arg| cx. expr_addr_of ( sp, self_arg) ) ;
1298+ let match_arg = cx. expr ( sp, ast:: ExprTup ( borrowed_self_args) ) ;
1299+
1300+ //Lastly we create an expression which branches on all discriminants being equal
1301+ // if discriminant_test {
1302+ // match (...) {
1303+ // (Variant1, Variant1, ...) => Body1
1304+ // (Variant2, Variant2, ...) => Body2,
1305+ // ...
1306+ // _ => ::core::intrinsics::unreachable()
1307+ // }
1308+ // }
1309+ // else {
1310+ // <delegated expression referring to __self0_vi, et al.>
1311+ // }
1312+ let all_match = cx. expr_match ( sp, match_arg, match_arms) ;
1313+ let arm_expr = cx. expr_if ( sp, discriminant_test, all_match, Some ( arm_expr) ) ;
1314+ cx. expr_block (
1315+ cx. block_all ( sp, index_let_stmts, Some ( arm_expr) ) )
12721316 } else if variants. is_empty ( ) {
12731317 // As an additional wrinkle, For a zero-variant enum A,
12741318 // currently the compiler
@@ -1319,17 +1363,19 @@ impl<'a> MethodDef<'a> {
13191363 // derive Debug on such a type could here generate code
13201364 // that needs the feature gate enabled.)
13211365
1322- return cx. expr_unreachable ( sp) ;
1366+ cx. expr_unreachable ( sp)
1367+ }
1368+ else {
1369+
1370+ // Final wrinkle: the self_args are expressions that deref
1371+ // down to desired l-values, but we cannot actually deref
1372+ // them when they are fed as r-values into a tuple
1373+ // expression; here add a layer of borrowing, turning
1374+ // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
1375+ let borrowed_self_args = self_args. move_map ( |self_arg| cx. expr_addr_of ( sp, self_arg) ) ;
1376+ let match_arg = cx. expr ( sp, ast:: ExprTup ( borrowed_self_args) ) ;
1377+ cx. expr_match ( sp, match_arg, match_arms)
13231378 }
1324-
1325- // Final wrinkle: the self_args are expressions that deref
1326- // down to desired l-values, but we cannot actually deref
1327- // them when they are fed as r-values into a tuple
1328- // expression; here add a layer of borrowing, turning
1329- // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
1330- let borrowed_self_args = self_args. move_map ( |self_arg| cx. expr_addr_of ( sp, self_arg) ) ;
1331- let match_arg = cx. expr ( sp, ast:: ExprTup ( borrowed_self_args) ) ;
1332- cx. expr_match ( sp, match_arg, match_arms)
13331379 }
13341380
13351381 fn expand_static_enum_method_body ( & self ,
0 commit comments