From 50fd0765b5e6150b026ed590a3b4771421751d2b Mon Sep 17 00:00:00 2001
From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>
Date: Thu, 3 Nov 2016 15:55:09 +0100
Subject: [PATCH] call drop "glue" for enums

---
 src/interpreter/terminator/mod.rs | 37 +++++++++++++++++++++++--------
 1 file changed, 28 insertions(+), 9 deletions(-)

diff --git a/src/interpreter/terminator/mod.rs b/src/interpreter/terminator/mod.rs
index 1b045417f4c..4e6be7fdec9 100644
--- a/src/interpreter/terminator/mod.rs
+++ b/src/interpreter/terminator/mod.rs
@@ -490,15 +490,34 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
         match ty.sty {
             ty::TyAdt(adt_def, substs) => {
                 // FIXME: some structs are represented as ByValPair
-                let ptr = self.force_allocation(lval)?.to_ptr();
-                if adt_def.is_univariant() {
-                    for (i, field_ty) in adt_def.struct_variant().fields.iter().enumerate() {
-                        let field_ty = self.monomorphize_field_ty(field_ty, substs);
-                        let offset = self.get_field_offset(ty, i)?.bytes() as isize;
-                        self.drop(Lvalue::from_ptr(ptr.offset(offset)), field_ty)?;
-                    }
-                } else {
-                    unimplemented!()
+                let adt_ptr = self.force_allocation(lval)?.to_ptr();
+                let layout = self.type_layout(ty);
+                let fields = match *layout {
+                    Layout::Univariant { ref variant, .. } => {
+                        adt_def.struct_variant().fields.iter().zip(&variant.offsets)
+                    },
+                    Layout::General { ref variants, .. } => {
+                        let discr_val = self.read_discriminant_value(adt_ptr, ty)?;
+                        match adt_def.variants.iter().position(|v| discr_val == v.disr_val.to_u64_unchecked()) {
+                            // start at offset 1, to skip over the discriminant
+                            Some(i) => adt_def.variants[i].fields.iter().zip(&variants[i].offsets[1..]),
+                            None => return Err(EvalError::InvalidDiscriminant),
+                        }
+                    },
+                    Layout::StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => {
+                        let discr = self.read_discriminant_value(adt_ptr, ty)?;
+                        if discr == nndiscr {
+                            adt_def.variants[discr as usize].fields.iter().zip(&nonnull.offsets)
+                        } else {
+                            // FIXME: the zst variant might contain zst types that impl Drop
+                            return Ok(()); // nothing to do, this is zero sized (e.g. `None`)
+                        }
+                    },
+                    _ => bug!("{:?} is not an adt layout", layout),
+                };
+                for (field_ty, offset) in fields {
+                    let field_ty = self.monomorphize_field_ty(field_ty, substs);
+                    self.drop(Lvalue::from_ptr(adt_ptr.offset(offset.bytes() as isize)), field_ty)?;
                 }
             },
             ty::TyTuple(fields) => {