diff --git a/src/rt/rust_cc.cpp b/src/rt/rust_cc.cpp
index 4befb36d819..146c1f514ba 100644
--- a/src/rt/rust_cc.cpp
+++ b/src/rt/rust_cc.cpp
@@ -169,7 +169,6 @@ irc::compute_ircs(rust_task *task, irc_map &ircs) {
         begin(task->local_allocs.begin()), end(task->local_allocs.end());
     while (begin != end) {
         uint8_t *p = reinterpret_cast<uint8_t *>(begin->first);
-        p += sizeof(uintptr_t); // Skip over the reference count.
 
         const type_desc *tydesc = begin->second;
 
@@ -178,9 +177,9 @@ irc::compute_ircs(rust_task *task, irc_map &ircs) {
 
         shape::arena arena;
         shape::type_param *params =
-            shape::type_param::from_tydesc(&tydesc, arena);
-        irc irc(task, true, tydesc->shape, params, tydesc->shape_tables, p,
-                ircs);
+            shape::type_param::from_tydesc_and_data(tydesc, p, arena);
+        irc irc(task, true, tydesc->shape, params, tydesc->shape_tables,
+                p + sizeof(uintptr_t), ircs);
         irc.walk();
 
 #if 0
@@ -374,26 +373,25 @@ mark::do_mark(rust_task *task, const std::vector<void *> &roots,
         if (marked.find(alloc) == marked.end()) {
             marked.insert(alloc);
 
-            uint8_t *p = reinterpret_cast<uint8_t *>(alloc);
-            p += sizeof(uintptr_t); // Skip over the reference count.
-
-            const type_desc *tydesc = task->local_allocs[*begin];
+            const type_desc *tydesc = task->local_allocs[alloc];
 
             //DPRINT("marking: %p, tydesc=%p\n", p, tydesc);
 
+            uint8_t *p = reinterpret_cast<uint8_t *>(alloc);
             shape::arena arena;
             shape::type_param *params =
-                shape::type_param::from_tydesc(&tydesc, arena);
+                shape::type_param::from_tydesc_and_data(tydesc, p, arena);
 
-#if 0
+            // We skip over the reference count here.
             shape::log log(task, true, tydesc->shape, params,
-                           tydesc->shape_tables, p, std::cerr);
+                           tydesc->shape_tables, p + sizeof(uintptr_t),
+                           std::cerr);
             log.walk();
             DPRINT("\n");
-#endif
 
+            // We skip over the reference count here.
             mark mark(task, true, tydesc->shape, params, tydesc->shape_tables,
-                      p, marked);
+                      p + sizeof(uintptr_t), marked);
             mark.walk();
         }
 
diff --git a/src/rt/rust_gc.cpp b/src/rt/rust_gc.cpp
index ae3c5a01031..26e48857ecb 100644
--- a/src/rt/rust_gc.cpp
+++ b/src/rt/rust_gc.cpp
@@ -105,7 +105,8 @@ gc::mark(std::vector<root> &roots) {
 
         shape::arena arena;
         shape::type_param *params =
-            shape::type_param::from_tydesc(&ri->tydesc, arena);
+            shape::type_param::from_tydesc_and_data(ri->tydesc, ri->data,
+                                                    arena);
         shape::log log(task, true, ri->tydesc->shape, params,
                        ri->tydesc->shape_tables, ri->data, std::cerr);
         log.walk();
diff --git a/src/rt/rust_obstack.cpp b/src/rt/rust_obstack.cpp
index 99e72489f5f..e8dbffd74a2 100644
--- a/src/rt/rust_obstack.cpp
+++ b/src/rt/rust_obstack.cpp
@@ -160,12 +160,13 @@ rust_obstack::dump() const {
     iterator b = begin(), e = end();
     while (b != e) {
         std::pair<const type_desc *,void *> data = *b;
+        uint8_t *dp = reinterpret_cast<uint8_t *>(data.second);
+
         shape::arena arena;
         shape::type_param *params =
-            shape::type_param::from_tydesc(&data.first, arena);
+            shape::type_param::from_tydesc_and_data(data.first, dp, arena);
         shape::log log(task, true, data.first->shape, params,
-                       data.first->shape_tables,
-                       reinterpret_cast<uint8_t *>(data.second), std::cerr);
+                       data.first->shape_tables, dp, std::cerr);
         log.walk();
         std::cerr << "\n";
 
diff --git a/src/rt/rust_shape.cpp b/src/rt/rust_shape.cpp
index d25c340264e..994c4df0fb9 100644
--- a/src/rt/rust_shape.cpp
+++ b/src/rt/rust_shape.cpp
@@ -37,7 +37,10 @@ type_param::make(const type_desc **tydescs, unsigned n_tydescs,
         const type_desc *subtydesc = tydescs[i];
         ptrs[i].shape = subtydesc->shape;
         ptrs[i].tables = subtydesc->shape_tables;
-        ptrs[i].params = from_tydesc(&subtydesc, arena);
+
+        // FIXME: Doesn't handle a type-parametric object closing over a
+        // type-parametric object type properly.
+        ptrs[i].params = from_tydesc(subtydesc, arena);
     }
     return ptrs;
 }
@@ -531,8 +534,12 @@ upcall_cmp_type(int8_t *result, rust_task *task, const type_desc *tydesc,
                 const type_desc **subtydescs, uint8_t *data_0,
                 uint8_t *data_1, uint8_t cmp_type) {
     shape::arena arena;
+
+    // FIXME: This may well be broken when comparing two closures or objects
+    // that close over different sets of type parameters.
     shape::type_param *params =
-        shape::type_param::from_tydesc(&tydesc, arena);
+        shape::type_param::from_tydesc_and_data(tydesc, data_0, arena);
+
     shape::cmp cmp(task, true, tydesc->shape, params, tydesc->shape_tables,
                    data_0, data_1);
     cmp.walk();
@@ -552,7 +559,7 @@ upcall_log_type(rust_task *task, const type_desc *tydesc, uint8_t *data,
 
     shape::arena arena;
     shape::type_param *params =
-        shape::type_param::from_tydesc(&tydesc, arena);
+        shape::type_param::from_tydesc_and_data(tydesc, data, arena);
 
     std::stringstream ss;
     shape::log log(task, true, tydesc->shape, params, tydesc->shape_tables,
diff --git a/src/rt/rust_shape.h b/src/rt/rust_shape.h
index 64859dbfa35..e71c5c8188f 100644
--- a/src/rt/rust_shape.h
+++ b/src/rt/rust_shape.h
@@ -310,27 +310,44 @@ public:
     }
 
     // Creates type parameters from a type descriptor.
-    static inline type_param *from_tydesc(const type_desc **tydesc,
+    static inline type_param *from_tydesc(const type_desc *tydesc,
                                           arena &arena) {
-        if ((*tydesc)->n_obj_params) {
-            uintptr_t n_obj_params = (*tydesc)->n_obj_params;
+        // In order to find the type parameters of objects and functions, we
+        // have to actually have the data pointer, since we don't statically
+        // know from the type of an object or function which type parameters
+        // it closes over.
+        assert(!tydesc->n_obj_params && "Type-parametric objects and "
+               "functions must go through from_tydesc_and_data() instead!");
+
+        return make(tydesc->first_param, tydesc->n_params, arena);
+    }
+
+    static type_param *from_tydesc_and_data(const type_desc *tydesc,
+                                            uint8_t *dp, arena &arena) {
+        if (tydesc->n_obj_params) {
+            uintptr_t n_obj_params = tydesc->n_obj_params;
             const type_desc **first_param;
             if (n_obj_params & 0x80000000) {
                 // Function closure.
                 DPRINT("n_obj_params FN %lu, tydesc %p, starting at %p\n",
-                       (unsigned long)n_obj_params, tydesc, tydesc + 4);
+                       (unsigned long)n_obj_params, tydesc,
+                       dp + sizeof(uintptr_t) + tydesc->size);
                 n_obj_params &= 0x7fffffff;
+                // FIXME: Is this right?
                 first_param = (const type_desc **)
-                    ((uint8_t *)(tydesc + 4) + (*tydesc)->size);
+                    (dp + sizeof(uintptr_t) + tydesc->size);
             } else {
                 // Object closure.
                 DPRINT("n_obj_params OBJ %lu, tydesc %p, starting at %p\n",
-                       (unsigned long)n_obj_params, tydesc, tydesc + 4);
-                first_param = tydesc + 4;
+                       (unsigned long)n_obj_params, tydesc,
+                       dp + sizeof(uintptr_t) * 2);
+                first_param = (const type_desc **)
+                    (dp + sizeof(uintptr_t) * 2);
             }
+            return make(first_param, n_obj_params, arena);
         }
 
-        return make((*tydesc)->first_param, (*tydesc)->n_params, arena);
+        return make(tydesc->first_param, tydesc->n_params, arena);
     }
 };