From 5593add3a8da4bb69ecbece5eaef91f01ca748f7 Mon Sep 17 00:00:00 2001 From: Elliott Slaughter Date: Fri, 24 Aug 2012 15:31:33 -0700 Subject: [PATCH] rustc: Break cyclical dependence between emit_tydescs and gen_shape_tables. Force all tydescs to be emitted before emit_tydescs to avoid linker failures. --- src/rustc/middle/trans/base.rs | 10 ++++++++++ src/rustc/middle/trans/common.rs | 3 +++ src/rustc/middle/trans/shape.rs | 28 ++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) 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::(), 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, discrim_symbols: hashmap, tydescs: hashmap, + // 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>, // 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);