about summary refs log tree commit diff
diff options
context:
space:
mode:
authorElliott Slaughter <eslaughter@mozilla.com>2012-08-24 15:31:33 -0700
committerElliott Slaughter <eslaughter@mozilla.com>2012-08-27 12:48:35 -0700
commit5593add3a8da4bb69ecbece5eaef91f01ca748f7 (patch)
tree78af200509e9069abccb5e9936de97eb3fd2fe57
parent785c524d3ecbb44760139c9a2deab8f897ab0426 (diff)
rustc: Break cyclical dependence between emit_tydescs and gen_shape_tables.
Force all tydescs to be emitted before emit_tydescs to avoid linker
failures.
-rw-r--r--src/rustc/middle/trans/base.rs10
-rw-r--r--src/rustc/middle/trans/common.rs3
-rw-r--r--src/rustc/middle/trans/shape.rs28
3 files changed, 41 insertions, 0 deletions
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 22d28c90fab..405a52cf7c8 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -531,6 +531,10 @@ fn declare_tydesc_addrspace(ccx: @crate_ctxt, t: ty::t) -> addrspace {
 // Generates the declaration for (but doesn't emit) a type descriptor.
 fn declare_tydesc(ccx: @crate_ctxt, t: ty::t) -> @tydesc_info {
     let _icx = ccx.insn_ctxt("declare_tydesc");
+    // If emit_tydescs already ran, then we shouldn't be creating any new
+    // tydescs.
+    assert !ccx.finished_tydescs;
+
     let llty = type_of(ccx, t);
 
     if ccx.sess.count_type_sizes() {
@@ -624,6 +628,8 @@ fn make_generic_glue(ccx: @crate_ctxt, t: ty::t, llfn: ValueRef,
 
 fn emit_tydescs(ccx: @crate_ctxt) {
     let _icx = ccx.insn_ctxt("emit_tydescs");
+    // As of this point, allow no more tydescs to be created.
+    ccx.finished_tydescs = true;
     for ccx.tydescs.each |key, val| {
         let glue_fn_ty = T_ptr(T_generic_glue_fn(ccx));
         let ti = val;
@@ -5927,6 +5933,7 @@ fn trans_crate(sess: session::session,
           discrims: ast_util::new_def_hash::<ValueRef>(),
           discrim_symbols: int_hash::<~str>(),
           tydescs: ty::new_ty_hash(),
+          mut finished_tydescs: false,
           external: ast_util::new_def_hash(),
           monomorphized: map::hashmap(hash_mono_id, sys::shape_eq),
           monomorphizing: ast_util::new_def_hash(),
@@ -5982,6 +5989,9 @@ fn trans_crate(sess: session::session,
     }
 
     fill_crate_map(ccx, crate_map);
+    // NB: Must call force_declare_tydescs before emit_tydescs to break
+    // cyclical dependency with shape code! See shape.rs for details.
+    force_declare_tydescs(ccx);
     emit_tydescs(ccx);
     gen_shape_tables(ccx);
     write_abi_version(ccx);
diff --git a/src/rustc/middle/trans/common.rs b/src/rustc/middle/trans/common.rs
index aabe76709b5..1a205929e5c 100644
--- a/src/rustc/middle/trans/common.rs
+++ b/src/rustc/middle/trans/common.rs
@@ -117,6 +117,9 @@ type crate_ctxt = {
      discrims: hashmap<ast::def_id, ValueRef>,
      discrim_symbols: hashmap<ast::node_id, ~str>,
      tydescs: hashmap<ty::t, @tydesc_info>,
+     // Set when running emit_tydescs to enforce that no more tydescs are
+     // created.
+     mut finished_tydescs: bool,
      // Track mapping of external ids to local items imported for inlining
      external: hashmap<ast::def_id, Option<ast::node_id>>,
      // Cache instances of monomorphized functions
diff --git a/src/rustc/middle/trans/shape.rs b/src/rustc/middle/trans/shape.rs
index 409d6c4f9d7..b0dce025f8e 100644
--- a/src/rustc/middle/trans/shape.rs
+++ b/src/rustc/middle/trans/shape.rs
@@ -584,6 +584,34 @@ fn gen_resource_shapes(ccx: @crate_ctxt) -> ValueRef {
     return mk_global(ccx, ~"resource_shapes", C_struct(dtors), true);
 }
 
+// This function serves to break a cyclical dependence between
+// emit_tydescs and gen_shape_tables.
+//
+//  * emit_tydescs calls shape_of, which causes changes to the shape
+//    tables
+//  * gen_shape_tables transitively calls get_tydesc, which causes new
+//    tydescs to be created
+//
+// We force those tydescs to be emitted now, thus breaking the
+// dependency.
+fn force_declare_tydescs(ccx: @crate_ctxt) {
+    // Walk all known tydescs first to force shape code to declare
+    // dependencies.
+    for ccx.tydescs.each |key, _val| {
+        shape_of(ccx, key);
+    }
+
+    // Then walk all resource shapes to force emit all dtors.
+    let len = ccx.shape_cx.resources.len();
+    for uint::range(0u, len) |i| {
+        let ri = ccx.shape_cx.resources.get(i);
+        for ri.tps.each() |s| { assert !ty::type_has_params(s); }
+        do option::iter(ri.parent_id) |id| {
+            trans::base::get_res_dtor(ccx, ri.did, id, ri.tps);
+        }
+    }
+}
+
 fn gen_shape_tables(ccx: @crate_ctxt) {
     let lltagstable = gen_enum_shapes(ccx);
     let llresourcestable = gen_resource_shapes(ccx);