diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 3a67296e86d..26daf479e42 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -3064,30 +3064,37 @@ tag copy_action { INIT; DROP_EXISTING; }
 
 fn copy_val(&@block_ctxt cx, copy_action action, ValueRef dst, ValueRef src,
             &ty::t t) -> result {
-    if (ty::type_is_scalar(cx.fcx.lcx.ccx.tcx, t) ||
-            ty::type_is_native(cx.fcx.lcx.ccx.tcx, t)) {
+    auto ccx = cx.fcx.lcx.ccx;
+    // FIXME this is just a clunky stopgap. we should do proper checking in an
+    // earlier pass.
+    if (!ty::type_is_copyable(ccx.tcx, t)) {
+        ccx.sess.span_err(cx.sp, "Copying a non-copyable type.");
+    }
+
+    if (ty::type_is_scalar(ccx.tcx, t) ||
+            ty::type_is_native(ccx.tcx, t)) {
         ret rslt(cx, cx.build.Store(src, dst));
-    } else if (ty::type_is_nil(cx.fcx.lcx.ccx.tcx, t) ||
-                   ty::type_is_bot(cx.fcx.lcx.ccx.tcx, t)) {
+    } else if (ty::type_is_nil(ccx.tcx, t) ||
+                   ty::type_is_bot(ccx.tcx, t)) {
         ret rslt(cx, C_nil());
-    } else if (ty::type_is_boxed(cx.fcx.lcx.ccx.tcx, t)) {
+    } else if (ty::type_is_boxed(ccx.tcx, t)) {
         auto r = take_ty(cx, src, t);
         if (action == DROP_EXISTING) {
             r = drop_ty(r.bcx, r.bcx.build.Load(dst), t);
         }
         ret rslt(r.bcx, r.bcx.build.Store(src, dst));
-    } else if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t) ||
-                   ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
+    } else if (ty::type_is_structural(ccx.tcx, t) ||
+                   ty::type_has_dynamic_size(ccx.tcx, t)) {
         auto r = take_ty(cx, src, t);
         if (action == DROP_EXISTING) { r = drop_ty(r.bcx, dst, t); }
         r = memmove_ty(r.bcx, dst, src, t);
-        if (ty::type_owns_heap_mem(cx.fcx.lcx.ccx.tcx, t)) {
+        if (ty::type_owns_heap_mem(ccx.tcx, t)) {
             r = duplicate_heap_parts(cx, dst, t);
         }
         ret r;
     }
-    cx.fcx.lcx.ccx.sess.bug("unexpected type in trans::copy_val: " +
-                                ty_to_str(cx.fcx.lcx.ccx.tcx, t));
+    ccx.sess.bug("unexpected type in trans::copy_val: " +
+                 ty_to_str(ccx.tcx, t));
 }
 
 
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index 0d5948eed6a..e8b31aa3a63 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -170,6 +170,7 @@ export type_is_scalar;
 export type_is_sequence;
 export type_is_signed;
 export type_is_structural;
+export type_is_copyable;
 export type_is_tup_like;
 export type_is_str;
 export type_owns_heap_mem;
@@ -896,6 +897,13 @@ fn type_is_structural(&ctxt cx, &t ty) -> bool {
     }
 }
 
+fn type_is_copyable(&ctxt cx, &t ty) -> bool {
+    ret alt (struct(cx, ty)) {
+        case (ty_res(_, _)) { false }
+        case (_) { true }
+    };
+}
+
 fn type_is_sequence(&ctxt cx, &t ty) -> bool {
     alt (struct(cx, ty)) {
         case (ty_str) { ret true; }