]> git.lizzy.rs Git - rust.git/blobdiff - src/discriminant.rs
Rustfmt
[rust.git] / src / discriminant.rs
index 1e8e86add1a59ad8fcc7d508a4c04018db488847..f619bb5ed5e586ae33f5b7711095613bdad14472 100644 (file)
@@ -7,7 +7,7 @@
 use crate::prelude::*;
 
 pub(crate) fn codegen_set_discriminant<'tcx>(
-    fx: &mut FunctionCx<'_, 'tcx, impl Module>,
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
     place: CPlace<'tcx>,
     variant_index: VariantIdx,
 ) {
@@ -26,31 +26,34 @@ pub(crate) fn codegen_set_discriminant<'tcx>(
             variants: _,
         } => {
             let ptr = place.place_field(fx, mir::Field::new(tag_field));
-            let to = layout
-                .ty
-                .discriminant_for_variant(fx.tcx, variant_index)
+            let to = layout.ty.discriminant_for_variant(fx.tcx, variant_index).unwrap().val;
+            let to = if ptr.layout().abi.is_signed() {
+                ty::ScalarInt::try_from_int(
+                    ptr.layout().size.sign_extend(to) as i128,
+                    ptr.layout().size,
+                )
                 .unwrap()
-                .val
-                .into();
+            } else {
+                ty::ScalarInt::try_from_uint(to, ptr.layout().size).unwrap()
+            };
             let discr = CValue::const_val(fx, ptr.layout(), to);
             ptr.write_cvalue(fx, discr);
         }
         Variants::Multiple {
             tag: _,
             tag_field,
-            tag_encoding:
-                TagEncoding::Niche {
-                    dataful_variant,
-                    ref niche_variants,
-                    niche_start,
-                },
+            tag_encoding: TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
             variants: _,
         } => {
             if variant_index != dataful_variant {
                 let niche = place.place_field(fx, mir::Field::new(tag_field));
                 let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
-                let niche_value = u128::from(niche_value).wrapping_add(niche_start);
-                let niche_llval = CValue::const_val(fx, niche.layout(), niche_value.into());
+                let niche_value = ty::ScalarInt::try_from_uint(
+                    u128::from(niche_value).wrapping_add(niche_start),
+                    niche.layout().size,
+                )
+                .unwrap();
+                let niche_llval = CValue::const_val(fx, niche.layout(), niche_value);
                 niche.write_cvalue(fx, niche_llval);
             }
         }
@@ -58,18 +61,17 @@ pub(crate) fn codegen_set_discriminant<'tcx>(
 }
 
 pub(crate) fn codegen_get_discriminant<'tcx>(
-    fx: &mut FunctionCx<'_, 'tcx, impl Module>,
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
     value: CValue<'tcx>,
     dest_layout: TyAndLayout<'tcx>,
 ) -> CValue<'tcx> {
     let layout = value.layout();
 
     if layout.abi == Abi::Uninhabited {
-        return trap_unreachable_ret_value(
-            fx,
-            dest_layout,
-            "[panic] Tried to get discriminant for uninhabited type.",
-        );
+        let true_ = fx.bcx.ins().iconst(types::I32, 1);
+        fx.bcx.ins().trapnz(true_, TrapCode::UnreachableCodeReached);
+        // Return a dummy value
+        return CValue::by_ref(Pointer::const_addr(fx, 0), dest_layout);
     }
 
     let (tag_scalar, tag_field, tag_encoding) = match &layout.variants {
@@ -78,14 +80,20 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
                 .ty
                 .discriminant_for_variant(fx.tcx, *index)
                 .map_or(u128::from(index.as_u32()), |discr| discr.val);
-            return CValue::const_val(fx, dest_layout, discr_val.into());
+            let discr_val = if dest_layout.abi.is_signed() {
+                ty::ScalarInt::try_from_int(
+                    dest_layout.size.sign_extend(discr_val) as i128,
+                    dest_layout.size,
+                )
+                .unwrap()
+            } else {
+                ty::ScalarInt::try_from_uint(discr_val, dest_layout.size).unwrap()
+            };
+            return CValue::const_val(fx, dest_layout, discr_val);
+        }
+        Variants::Multiple { tag, tag_field, tag_encoding, variants: _ } => {
+            (tag, *tag_field, tag_encoding)
         }
-        Variants::Multiple {
-            tag,
-            tag_field,
-            tag_encoding,
-            variants: _,
-        } => (tag, *tag_field, tag_encoding),
     };
 
     let cast_to = fx.clif_type(dest_layout.ty).unwrap();
@@ -97,18 +105,14 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
     // Decode the discriminant (specifically if it's niche-encoded).
     match *tag_encoding {
         TagEncoding::Direct => {
-            let signed = match tag_scalar.value {
+            let signed = match tag_scalar.primitive() {
                 Int(_, signed) => signed,
                 _ => false,
             };
             let val = clif_intcast(fx, tag, cast_to, signed);
             CValue::by_val(val, dest_layout)
         }
-        TagEncoding::Niche {
-            dataful_variant,
-            ref niche_variants,
-            niche_start,
-        } => {
+        TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
             // Rebase from niche values to discriminants, and check
             // whether the result is in range for the niche variants.
 
@@ -124,10 +128,16 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
             let relative_discr = if niche_start == 0 {
                 tag
             } else {
-                // FIXME handle niche_start > i64::MAX
-                fx.bcx
-                    .ins()
-                    .iadd_imm(tag, -i64::try_from(niche_start).unwrap())
+                let niche_start = match fx.bcx.func.dfg.value_type(tag) {
+                    types::I128 => {
+                        let lsb = fx.bcx.ins().iconst(types::I64, niche_start as u64 as i64);
+                        let msb =
+                            fx.bcx.ins().iconst(types::I64, (niche_start >> 64) as u64 as i64);
+                        fx.bcx.ins().iconcat(lsb, msb)
+                    }
+                    ty => fx.bcx.ins().iconst(ty, niche_start as i64),
+                };
+                fx.bcx.ins().isub(tag, niche_start)
             };
             let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
             let is_niche = {
@@ -155,15 +165,10 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
                 } else {
                     clif_intcast(fx, relative_discr, cast_to, false)
                 };
-                fx.bcx
-                    .ins()
-                    .iadd_imm(relative_discr, i64::from(niche_variants.start().as_u32()))
+                fx.bcx.ins().iadd_imm(relative_discr, i64::from(niche_variants.start().as_u32()))
             };
 
-            let dataful_variant = fx
-                .bcx
-                .ins()
-                .iconst(cast_to, i64::from(dataful_variant.as_u32()));
+            let dataful_variant = fx.bcx.ins().iconst(cast_to, i64::from(dataful_variant.as_u32()));
             let discr = fx.bcx.ins().select(is_niche, niche_discr, dataful_variant);
             CValue::by_val(discr, dest_layout)
         }