about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDaniel Micay <danielmicay@gmail.com>2013-09-26 16:54:15 -0400
committerDaniel Micay <danielmicay@gmail.com>2013-09-26 17:27:23 -0400
commitc3e4e068416438e91e3e9809ee8553a764d8e26e (patch)
tree6a04956609a6b378b1eb56a28f70003bcb885ee7
parent47f2e80b65bf814953c0ceda3b48e46802883f4b (diff)
downloadrust-c3e4e068416438e91e3e9809ee8553a764d8e26e.tar.gz
rust-c3e4e068416438e91e3e9809ee8553a764d8e26e.zip
remove type_use
This is broken, and results in poor performance due to the undefined
behaviour in the LLVM IR. LLVM's `mergefunc` is a *much* better way of
doing this since it merges based on the equality of the bytecode.

For example, consider `std::repr`. It generates different code per
type, but is not included in the type bounds of generics.

The `mergefunc` pass works for most of our code but currently hits an
assert on libstd. It is receiving attention upstream so it will be
ready soon, but I don't think removing this broken code should wait any
longer. I've opened #9536 about enabling it by default.

Closes #8651
Closes #3547
Closes #2537
Closes #6971
Closes #9222
-rwxr-xr-xsrc/etc/monodebug.pl79
-rw-r--r--src/etc/zsh/_rust1
-rw-r--r--src/librustc/driver/driver.rs7
-rw-r--r--src/librustc/driver/session.rs32
-rw-r--r--src/librustc/middle/trans/context.rs4
-rw-r--r--src/librustc/middle/trans/meth.rs3
-rw-r--r--src/librustc/middle/trans/mod.rs1
-rw-r--r--src/librustc/middle/trans/monomorphize.rs71
-rw-r--r--src/librustc/middle/trans/type_use.rs449
9 files changed, 21 insertions, 626 deletions
diff --git a/src/etc/monodebug.pl b/src/etc/monodebug.pl
deleted file mode 100755
index a2d27591cad..00000000000
--- a/src/etc/monodebug.pl
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/usr/bin/perl
-
-#
-# This is a tool that helps with debugging incorrect monomorphic instance collapse.
-#
-# To use:
-#    $ RUST_LOG=rustc::middle::trans::monomorphize rustc ARGS 2>&1 >log.txt
-#    $ ./monodebug.pl log.txt
-#
-# This will show all generics that got collapsed. You can inspect this list to find the instances
-# that were mistakenly combined into one. Fixes will (most likely) be applied to type_use.rs.
-#
-# Questions about this tool go to pcwalton.
-#
-
-use strict;
-use warnings;
-use Data::Dumper qw(Dumper);
-use Text::Balanced qw(extract_bracketed);
-
-my %funcs;
-while (<>) {
-    chomp;
-    /^rust: ~"monomorphic_fn\((.*)"$/ or next;
-    my $text = $1;
-    $text =~ /fn_id=(\{ crate: \d+, node: \d+ \} \([^)]+\)), real_substs=(.*?), substs=(.*?), hash_id = \@\{ (.*) \}$/ or next;
-    my ($fn_id, $real_substs, $substs, $hash_id) = ($1, $2, $3, $4);
-
-    #print "$hash_id\n";
-    $hash_id =~ /^def: { crate: \d+, node: \d+ }, params: ~\[ (.*) \], impl_did_opt: (?:None|Some\({ crate: \d+, node: \d+ }\))$/ or next;
-    my $params = $1;
-
-    my @real_substs;
-    @real_substs = $real_substs =~ /\\"(.*?)\\"/g;
-
-    my @mono_params;
-    while (1) {
-        $params =~ s/^, //;
-        if ($params =~ s/^mono_precise//) {
-            extract_bracketed($params, '()');
-            push @mono_params, 'precise';
-            next;
-        }
-        if ($params =~ s/^mono_repr//) {
-            my $sub = extract_bracketed($params, '()');
-            push @mono_params, "repr($sub)";
-            next;
-        }
-        if ($params =~ s/^mono_any//) {
-            push @mono_params, "any";
-            next;
-        }
-        last;
-    }
-
-    my @key_params;
-    for (my $i = 0; $i < @mono_params; ++$i) {
-        if ($mono_params[$i] eq 'precise') {
-            push @key_params, 'precise(' . $real_substs[$i] . ')';
-        } else {
-            push @key_params, $mono_params[$i];
-        }
-    }
-
-    my $key = "$fn_id with " . (join ', ', @key_params);
-    $funcs{$key}{$real_substs} = 1;
-}
-
-while (my ($key, $substs) = each %funcs) {
-    my @params = keys %$substs;
-    next if @params == 1;
-
-    print "$key\n";
-    print(('-' x (length $key)), $/);
-    for my $param (@params) {
-        print "$param\n";
-    }
-    print "\n";
-}
diff --git a/src/etc/zsh/_rust b/src/etc/zsh/_rust
index 3d0163d9e25..a4b1bc629d1 100644
--- a/src/etc/zsh/_rust
+++ b/src/etc/zsh/_rust
@@ -71,7 +71,6 @@ _rustc_opts_debug=(
     'count-type-sizes:count the sizes of aggregate types'
     'meta-stats:gather metadata statistics'
     'no-opt:do not optimize, even if -O is passed'
-    'no-monomorphic-collapse:do not collapse template instantiations'
     'print-link-args:Print the arguments passed to the linker'
     'gc:Garbage collect shared data (experimental)'
     'jit:Execute using JIT (experimental)'
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index 5518dde0ee9..df3a40c2289 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -748,13 +748,6 @@ pub fn build_session_options(binary: @str,
     let debuginfo = debugging_opts & session::debug_info != 0 ||
         extra_debuginfo;
 
-    // If debugging info is generated, do not collapse monomorphized function instances.
-    // Functions with equivalent llvm code still need separate debugging descriptions because names
-    // might differ.
-    if debuginfo {
-        debugging_opts |= session::no_monomorphic_collapse;
-    }
-
     let statik = debugging_opts & session::statik != 0;
 
     let addl_lib_search_paths = matches.opt_strs("L").map(|s| Path(*s));
diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs
index 7f3f1f88a52..19e866c70a3 100644
--- a/src/librustc/driver/session.rs
+++ b/src/librustc/driver/session.rs
@@ -67,20 +67,19 @@ pub static debug_llvm:              uint = 1 << 13;
 pub static count_type_sizes:        uint = 1 << 14;
 pub static meta_stats:              uint = 1 << 15;
 pub static no_opt:                  uint = 1 << 16;
-pub static no_monomorphic_collapse: uint = 1 << 17;
-pub static gc:                      uint = 1 << 18;
-pub static jit:                     uint = 1 << 19;
-pub static debug_info:              uint = 1 << 20;
-pub static extra_debug_info:        uint = 1 << 21;
-pub static statik:                  uint = 1 << 22;
-pub static print_link_args:         uint = 1 << 23;
-pub static no_debug_borrows:        uint = 1 << 24;
-pub static lint_llvm:               uint = 1 << 25;
-pub static once_fns:                uint = 1 << 26;
-pub static print_llvm_passes:       uint = 1 << 27;
-pub static no_vectorize_loops:      uint = 1 << 28;
-pub static no_vectorize_slp:        uint = 1 << 29;
-pub static no_prepopulate_passes:   uint = 1 << 30;
+pub static gc:                      uint = 1 << 17;
+pub static jit:                     uint = 1 << 18;
+pub static debug_info:              uint = 1 << 19;
+pub static extra_debug_info:        uint = 1 << 20;
+pub static statik:                  uint = 1 << 21;
+pub static print_link_args:         uint = 1 << 22;
+pub static no_debug_borrows:        uint = 1 << 23;
+pub static lint_llvm:               uint = 1 << 24;
+pub static once_fns:                uint = 1 << 25;
+pub static print_llvm_passes:       uint = 1 << 26;
+pub static no_vectorize_loops:      uint = 1 << 27;
+pub static no_vectorize_slp:        uint = 1 << 28;
+pub static no_prepopulate_passes:   uint = 1 << 29;
 
 pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
     ~[(~"verbose", ~"in general, enable more debug printouts", verbose),
@@ -106,8 +105,6 @@ pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
       count_type_sizes),
      (~"meta-stats", ~"gather metadata statistics", meta_stats),
      (~"no-opt", ~"do not optimize, even if -O is passed", no_opt),
-     (~"no-monomorphic-collapse", ~"do not collapse template instantiations",
-      no_monomorphic_collapse),
      (~"print-link-args", ~"Print the arguments passed to the linker", print_link_args),
      (~"gc", ~"Garbage collect shared data (experimental)", gc),
      (~"jit", ~"Execute using JIT (experimental)", jit),
@@ -326,9 +323,6 @@ impl Session_ {
     pub fn borrowck_note_loan(&self) -> bool {
         self.debugging_opt(borrowck_note_loan)
     }
-    pub fn no_monomorphic_collapse(&self) -> bool {
-        self.debugging_opt(no_monomorphic_collapse)
-    }
     pub fn debug_borrows(&self) -> bool {
         self.opts.optimize == No && !self.debugging_opt(no_debug_borrows)
     }
diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs
index 134db45be43..36757374b0b 100644
--- a/src/librustc/middle/trans/context.rs
+++ b/src/librustc/middle/trans/context.rs
@@ -22,7 +22,6 @@ use middle::trans::adt;
 use middle::trans::base;
 use middle::trans::builder::Builder;
 use middle::trans::debuginfo;
-use middle::trans::type_use;
 use middle::trans::common::{C_i32, C_null};
 use middle::ty;
 
@@ -73,8 +72,6 @@ pub struct CrateContext {
      // Cache instances of monomorphized functions
      monomorphized: HashMap<mono_id, ValueRef>,
      monomorphizing: HashMap<ast::DefId, uint>,
-     // Cache computed type parameter uses (see type_use.rs)
-     type_use_cache: HashMap<ast::DefId, @~[type_use::type_uses]>,
      // Cache generated vtables
      vtables: HashMap<(ty::t, mono_id), ValueRef>,
      // Cache of constant strings,
@@ -204,7 +201,6 @@ impl CrateContext {
                   non_inlineable_statics: HashSet::new(),
                   monomorphized: HashMap::new(),
                   monomorphizing: HashMap::new(),
-                  type_use_cache: HashMap::new(),
                   vtables: HashMap::new(),
                   const_cstr_cache: HashMap::new(),
                   const_globals: HashMap::new(),
diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs
index fd35d05f0fd..ce4c1011e80 100644
--- a/src/librustc/middle/trans/meth.rs
+++ b/src/librustc/middle/trans/meth.rs
@@ -520,8 +520,7 @@ pub fn vtable_id(ccx: @mut CrateContext,
             monomorphize::make_mono_id(
                 ccx,
                 impl_id,
-                &psubsts,
-                None)
+                &psubsts)
         }
 
         // can't this be checked at the callee?
diff --git a/src/librustc/middle/trans/mod.rs b/src/librustc/middle/trans/mod.rs
index 008da7f7ff8..f55360213c6 100644
--- a/src/librustc/middle/trans/mod.rs
+++ b/src/librustc/middle/trans/mod.rs
@@ -38,7 +38,6 @@ pub mod foreign;
 pub mod intrinsic;
 pub mod reflect;
 pub mod debuginfo;
-pub mod type_use;
 pub mod machine;
 pub mod adt;
 pub mod asm;
diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs
index ef055a52468..034320008cd 100644
--- a/src/librustc/middle/trans/monomorphize.rs
+++ b/src/librustc/middle/trans/monomorphize.rs
@@ -18,15 +18,11 @@ use middle::trans::base::{trans_fn, decl_internal_rust_fn};
 use middle::trans::base::{get_item_val, no_self};
 use middle::trans::base;
 use middle::trans::common::*;
-use middle::trans::datum;
-use middle::trans::machine;
 use middle::trans::meth;
-use middle::trans::type_of;
-use middle::trans::type_use;
 use middle::trans::intrinsic;
 use middle::ty;
 use middle::typeck;
-use util::ppaux::{Repr,ty_to_str};
+use util::ppaux::Repr;
 
 use syntax::ast;
 use syntax::ast_map;
@@ -65,10 +61,8 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
 
     for s in real_substs.tps.iter() { assert!(!ty::type_has_params(*s)); }
     for s in psubsts.tys.iter() { assert!(!ty::type_has_params(*s)); }
-    let param_uses = type_use::type_uses_for(ccx, fn_id, psubsts.tys.len());
 
-
-    let hash_id = make_mono_id(ccx, fn_id, &*psubsts, Some(param_uses));
+    let hash_id = make_mono_id(ccx, fn_id, &*psubsts);
     if hash_id.params.iter().any(
                 |p| match *p { mono_precise(_, _) => false, _ => true }) {
         must_cast = true;
@@ -302,8 +296,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
 
 pub fn make_mono_id(ccx: @mut CrateContext,
                     item: ast::DefId,
-                    substs: &param_substs,
-                    param_uses: Option<@~[type_use::type_uses]>) -> mono_id {
+                    substs: &param_substs) -> mono_id {
     // FIXME (possibly #5801): Need a lot of type hints to get
     // .collect() to work.
     let substs_iter = substs.self_ty.iter().chain(substs.tys.iter());
@@ -321,59 +314,9 @@ pub fn make_mono_id(ccx: @mut CrateContext,
     };
 
 
-    let param_ids = match param_uses {
-      Some(ref uses) => {
-        // param_uses doesn't include a use for the self type.
-        // We just say it is fully used.
-        let self_use =
-            substs.self_ty.map(|_| type_use::use_repr|type_use::use_tydesc);
-        let uses_iter = self_use.iter().chain(uses.iter());
-
-        precise_param_ids.iter().zip(uses_iter).map(|(id, uses)| {
-            if ccx.sess.no_monomorphic_collapse() {
-                match *id {
-                    (a, b) => mono_precise(a, b)
-                }
-            } else {
-                match *id {
-                    (a, b@Some(_)) => mono_precise(a, b),
-                    (subst, None) => {
-                        if *uses == 0 {
-                            mono_any
-                        } else if *uses == type_use::use_repr &&
-                            !ty::type_needs_drop(ccx.tcx, subst)
-                        {
-                            let llty = type_of::type_of(ccx, subst);
-                            let size = machine::llbitsize_of_real(ccx, llty);
-                            let align = machine::llalign_of_min(ccx, llty);
-                            let mode = datum::appropriate_mode(ccx.tcx, subst);
-                            let data_class = mono_data_classify(subst);
-
-                            debug!("make_mono_id: type %s -> size %u align %u mode %? class %?",
-                                  ty_to_str(ccx.tcx, subst),
-                                  size, align, mode, data_class);
-
-                            // Special value for nil to prevent problems
-                            // with undef return pointers.
-                            if size <= 8u && ty::type_is_nil(subst) {
-                                mono_repr(0u, 0u, data_class, mode)
-                            } else {
-                                mono_repr(size, align, data_class, mode)
-                            }
-                        } else {
-                            mono_precise(subst, None)
-                        }
-                    }
-                }
-            }
-        }).collect()
-      }
-      None => {
-          precise_param_ids.iter().map(|x| {
-              let (a, b) = *x;
-              mono_precise(a, b)
-          }).collect()
-      }
-    };
+    let param_ids = precise_param_ids.iter().map(|x| {
+        let (a, b) = *x;
+        mono_precise(a, b)
+    }).collect();
     @mono_id_ {def: item, params: param_ids}
 }
diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs
deleted file mode 100644
index 6ae196226d5..00000000000
--- a/src/librustc/middle/trans/type_use.rs
+++ /dev/null
@@ -1,449 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Determines the ways in which a generic function body depends
-// on its type parameters. Used to aggressively reuse compiled
-// function bodies for different types.
-
-// This unfortunately depends on quite a bit of knowledge about the
-// details of the language semantics, and is likely to accidentally go
-// out of sync when something is changed. It could be made more
-// powerful by distinguishing between functions that only need to know
-// the size and alignment of a type, and those that also use its
-// drop/take glue. But this would increase the fragility of the code
-// to a ridiculous level, and probably not catch all that many extra
-// opportunities for reuse.
-
-// (An other approach to doing what this code does is to instrument
-// the translation code to set flags whenever it does something like
-// alloca a type or get a tydesc. This would not duplicate quite as
-// much information, but have the disadvantage of being very
-// invasive.)
-
-use middle::freevars;
-use middle::trans::common::*;
-use middle::trans::inline;
-use middle::ty;
-use middle::typeck;
-
-use std::option::{Some, None};
-use std::vec;
-use extra::list::{List, Cons, Nil};
-use extra::list;
-use syntax::ast;
-use syntax::ast::*;
-use syntax::ast_map;
-use syntax::ast_util;
-use syntax::parse::token;
-use syntax::visit;
-use syntax::visit::Visitor;
-
-pub type type_uses = uint; // Bitmask
-pub static use_repr: uint = 1;   /* Dependency on size/alignment/mode and
-                                     take/drop glue */
-pub static use_tydesc: uint = 2; /* Takes the tydesc, or compares */
-pub static use_all: uint = use_repr|use_tydesc;
-
-#[deriving(Clone)]
-pub struct Context {
-    ccx: @mut CrateContext,
-    uses: @mut ~[type_uses]
-}
-
-pub fn type_uses_for(ccx: @mut CrateContext, fn_id: DefId, n_tps: uint)
-    -> @~[type_uses] {
-
-    fn store_type_uses(cx: Context, fn_id: DefId) -> @~[type_uses] {
-        let Context { uses, ccx } = cx;
-        let uses = @(*uses).clone(); // freeze
-        ccx.type_use_cache.insert(fn_id, uses);
-        uses
-    }
-
-    match ccx.type_use_cache.find(&fn_id) {
-      Some(uses) => return *uses,
-      None => ()
-    }
-
-    let fn_id_loc = if fn_id.crate == LOCAL_CRATE {
-        fn_id
-    } else {
-        inline::maybe_instantiate_inline(ccx, fn_id)
-    };
-
-    // Conservatively assume full use for recursive loops
-    ccx.type_use_cache.insert(fn_id, @vec::from_elem(n_tps, use_all));
-
-    let mut cx = Context {
-        ccx: ccx,
-        uses: @mut vec::from_elem(n_tps, 0u)
-    };
-
-    // If the method is a default method, we mark all of the types as
-    // used.  This is imprecise, but simple. Getting it right is
-    // tricky because the substs on the call and the substs on the
-    // default method differ, because of substs on the trait/impl.
-    let is_default = ty::provided_source(ccx.tcx, fn_id_loc).is_some();
-    // We also mark all of the params as used if it is an extern thing
-    // that we haven't been able to inline yet.
-    if is_default || fn_id_loc.crate != LOCAL_CRATE {
-        for n in range(0u, n_tps) { cx.uses[n] |= use_all; }
-        return store_type_uses(cx, fn_id);
-    }
-
-    let map_node = match ccx.tcx.items.find(&fn_id_loc.node) {
-        Some(x) => {
-            (*x).clone()
-        }
-        None => {
-            ccx.sess.bug(fmt!("type_uses_for: unbound item ID %?",
-                              fn_id_loc))
-        }
-    };
-
-    match map_node {
-      ast_map::node_item(@ast::item { node: item_fn(_, _, _, _, ref body),
-                                      _ }, _) |
-      ast_map::node_method(@ast::method {body: ref body, _}, _, _) => {
-        handle_body(&mut cx, body);
-      }
-      ast_map::node_trait_method(*) => {
-        // This will be a static trait method. For now, we just assume
-        // it fully depends on all of the type information. (Doing
-        // otherwise would require finding the actual implementation).
-        for n in range(0u, n_tps) { cx.uses[n] |= use_all;}
-        // We need to return early, before the arguments are processed,
-        // because of difficulties in the handling of Self.
-        return store_type_uses(cx, fn_id);
-      }
-      ast_map::node_variant(_, _, _) => {
-        for n in range(0u, n_tps) { cx.uses[n] |= use_repr;}
-      }
-      ast_map::node_foreign_item(i@@foreign_item {
-            node: foreign_item_fn(*),
-            _
-        },
-        abi,
-        _,
-        _) => {
-        if abi.is_intrinsic() {
-            let nm = cx.ccx.sess.str_of(i.ident);
-            let name = nm.as_slice();
-            let flags = if name.starts_with("atomic_") {
-                0
-            } else {
-                match name {
-                    "size_of"  | "pref_align_of" | "min_align_of" |
-                    "uninit"   | "init" | "transmute" | "move_val" |
-                    "move_val_init" => use_repr,
-
-                    "get_tydesc" | "needs_drop" | "contains_managed" => use_tydesc,
-
-                    "visit_tydesc"  | "forget" | "frame_address" |
-                    "morestack_addr" => 0,
-
-                    "offset" |
-                    "memcpy32" | "memcpy64" | "memmove32" | "memmove64" |
-                    "memset32" | "memset64" => use_repr,
-
-                    "sqrtf32" | "sqrtf64" | "powif32" | "powif64" |
-                    "sinf32"  | "sinf64"  | "cosf32"  | "cosf64"  |
-                    "powf32"  | "powf64"  | "expf32"  | "expf64"  |
-                    "exp2f32" | "exp2f64" | "logf32"  | "logf64"  |
-                    "log10f32"| "log10f64"| "log2f32" | "log2f64" |
-                    "fmaf32"  | "fmaf64"  | "fabsf32" | "fabsf64" |
-                    "floorf32"| "floorf64"| "ceilf32" | "ceilf64" |
-                    "truncf32"| "truncf64" => 0,
-
-                    "ctpop8" | "ctpop16" | "ctpop32" | "ctpop64" => 0,
-
-                    "ctlz8" | "ctlz16" | "ctlz32" | "ctlz64" => 0,
-                    "cttz8" | "cttz16" | "cttz32" | "cttz64" => 0,
-
-                    "bswap16" | "bswap32" | "bswap64" => 0,
-
-
-                    "i8_add_with_overflow"  | "u8_add_with_overflow" |
-                    "i16_add_with_overflow" | "u16_add_with_overflow" |
-                    "i32_add_with_overflow" | "u32_add_with_overflow" |
-                    "i64_add_with_overflow" | "u64_add_with_overflow" => 0,
-
-                    "i8_sub_with_overflow"  | "u8_sub_with_overflow" |
-                    "i16_sub_with_overflow" | "u16_sub_with_overflow" |
-                    "i32_sub_with_overflow" | "u32_sub_with_overflow" |
-                    "i64_sub_with_overflow" | "u64_sub_with_overflow" => 0,
-
-                    "i8_mul_with_overflow"  | "u8_mul_with_overflow" |
-                    "i16_mul_with_overflow" | "u16_mul_with_overflow" |
-                    "i32_mul_with_overflow" | "u32_mul_with_overflow" |
-                    "i64_mul_with_overflow" | "u64_mul_with_overflow" => 0,
-
-                    // would be cool to make these an enum instead of
-                    // strings!
-                    _ => fail!("unknown intrinsic in type_use")
-                }
-            };
-            for n in range(0u, n_tps) { cx.uses[n] |= flags;}
-        }
-      }
-      ast_map::node_struct_ctor(*) => {
-        // Similarly to node_variant, this monomorphized function just
-        // uses the representations of all of its type parameters.
-        for n in range(0u, n_tps) { cx.uses[n] |= use_repr; }
-      }
-      _ => {
-        ccx.tcx.sess.bug(fmt!("unknown node type in type_use: %s",
-                              ast_map::node_id_to_str(
-                                ccx.tcx.items,
-                                fn_id_loc.node,
-                                token::get_ident_interner())));
-      }
-    }
-
-    // Now handle arguments
-    match ty::get(ty::lookup_item_type(cx.ccx.tcx, fn_id).ty).sty {
-        ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, _}) |
-        ty::ty_closure(ty::ClosureTy {sig: ref sig, _}) => {
-            for arg in sig.inputs.iter() {
-                type_needs(&cx, use_repr, *arg);
-            }
-        }
-        _ => ()
-    }
-
-    store_type_uses(cx, fn_id)
-}
-
-pub fn type_needs(cx: &Context, use_: uint, ty: ty::t) {
-    // Optimization -- don't descend type if all params already have this use
-    if cx.uses.iter().any(|&elt| elt & use_ != use_) {
-        type_needs_inner(cx, use_, ty, @Nil);
-    }
-}
-
-pub fn type_needs_inner(cx: &Context,
-                        use_: uint,
-                        ty: ty::t,
-                        enums_seen: @List<DefId>) {
-    do ty::maybe_walk_ty(ty) |ty| {
-        if ty::type_has_params(ty) {
-            match ty::get(ty).sty {
-                /*
-                 This previously included ty_box -- that was wrong
-                 because if we cast an @T to an trait (for example) and return
-                 it, we depend on the drop glue for T (we have to write the
-                 right tydesc into the result)
-                 */
-                ty::ty_closure(*) |
-                ty::ty_bare_fn(*) |
-                ty::ty_ptr(_) |
-                ty::ty_rptr(_, _) |
-                ty::ty_trait(*) => false,
-
-              ty::ty_enum(did, ref substs) => {
-                if list::find(enums_seen, |id| *id == did).is_none() {
-                    let seen = @Cons(did, enums_seen);
-                    let r = ty::enum_variants(cx.ccx.tcx, did);
-                    for v in r.iter() {
-                        for aty in v.args.iter() {
-                            let t = ty::subst(cx.ccx.tcx, &(*substs), *aty);
-                            type_needs_inner(cx, use_, t, seen);
-                        }
-                    }
-                }
-                false
-              }
-              ty::ty_param(p) => {
-                cx.uses[p.idx] |= use_;
-                false
-              }
-              _ => true
-            }
-        } else { false }
-    }
-}
-
-pub fn node_type_needs(cx: &Context, use_: uint, id: NodeId) {
-    type_needs(cx, use_, ty::node_id_to_type(cx.ccx.tcx, id));
-}
-
-pub fn mark_for_method_call(cx: &Context, e_id: NodeId, callee_id: NodeId) {
-    let mut opt_static_did = None;
-    {
-        let r = cx.ccx.maps.method_map.find(&e_id);
-        for mth in r.iter() {
-            match mth.origin {
-              typeck::method_static(did) => {
-                  opt_static_did = Some(did);
-              }
-              typeck::method_param(typeck::method_param {
-                  param_num: typeck::param_numbered(param),
-                  _
-              }) => {
-                cx.uses[param] |= use_tydesc;
-              }
-              _ => (),
-            }
-        }
-    }
-
-    // Note: we do not execute this code from within the each() call
-    // above because the recursive call to `type_needs` can trigger
-    // inlining and hence can cause `method_map` and
-    // `node_type_substs` to be modified.
-    for &did in opt_static_did.iter() {
-        {
-            let r = cx.ccx.tcx.node_type_substs.find_copy(&callee_id);
-            for ts in r.iter() {
-                let type_uses = type_uses_for(cx.ccx, did, ts.len());
-                for (uses, subst) in type_uses.iter().zip(ts.iter()) {
-                    type_needs(cx, *uses, *subst)
-                }
-            }
-        }
-    }
-}
-
-pub fn mark_for_expr(cx: &Context, e: &Expr) {
-    match e.node {
-      ExprVstore(_, _) | ExprVec(_, _) | ExprStruct(*) | ExprTup(_) |
-      ExprUnary(_, UnBox(_), _) | ExprUnary(_, UnUniq, _) |
-      ExprBinary(_, BiAdd, _, _) | ExprRepeat(*) => {
-        node_type_needs(cx, use_repr, e.id);
-      }
-      ExprCast(base, _) => {
-        let result_t = ty::node_id_to_type(cx.ccx.tcx, e.id);
-        match ty::get(result_t).sty {
-            ty::ty_trait(*) => {
-              // When we're casting to an trait, we need the
-              // tydesc for the expr that's being cast.
-              node_type_needs(cx, use_tydesc, base.id);
-            }
-            _ => ()
-        }
-      }
-      ExprBinary(_, op, lhs, _) => {
-        match op {
-          BiEq | BiLt | BiLe | BiNe | BiGe | BiGt => {
-            node_type_needs(cx, use_tydesc, lhs.id)
-          }
-          _ => ()
-        }
-      }
-      ExprPath(_) | ExprSelf => {
-        let opt_ts = cx.ccx.tcx.node_type_substs.find_copy(&e.id);
-        for ts in opt_ts.iter() {
-            let id = ast_util::def_id_of_def(cx.ccx.tcx.def_map.get_copy(&e.id));
-            let uses_for_ts = type_uses_for(cx.ccx, id, ts.len());
-            for (uses, subst) in uses_for_ts.iter().zip(ts.iter()) {
-                type_needs(cx, *uses, *subst)
-            }
-        }
-      }
-      ExprFnBlock(*) => {
-          match ty::ty_closure_sigil(ty::expr_ty(cx.ccx.tcx, e)) {
-              ast::OwnedSigil => {}
-              ast::BorrowedSigil | ast::ManagedSigil => {
-                  for fv in freevars::get_freevars(cx.ccx.tcx, e.id).iter() {
-                      let node_id = ast_util::def_id_of_def(fv.def).node;
-                      node_type_needs(cx, use_repr, node_id);
-                  }
-              }
-          }
-      }
-      ExprAssign(val, _) | ExprAssignOp(_, _, val, _) |
-      ExprRet(Some(val)) => {
-        node_type_needs(cx, use_repr, val.id);
-      }
-      ExprIndex(callee_id, base, _) => {
-        // FIXME (#2537): could be more careful and not count fields after
-        // the chosen field.
-        let base_ty = ty::node_id_to_type(cx.ccx.tcx, base.id);
-        type_needs(cx, use_repr, ty::type_autoderef(cx.ccx.tcx, base_ty));
-        mark_for_method_call(cx, e.id, callee_id);
-      }
-      ExprField(base, _, _) => {
-        // Method calls are now a special syntactic form,
-        // so `a.b` should always be a field.
-        assert!(!cx.ccx.maps.method_map.contains_key(&e.id));
-
-        let base_ty = ty::node_id_to_type(cx.ccx.tcx, base.id);
-        type_needs(cx, use_repr, ty::type_autoderef(cx.ccx.tcx, base_ty));
-      }
-      ExprCall(f, _, _) => {
-          let r = ty::ty_fn_args(ty::node_id_to_type(cx.ccx.tcx, f.id));
-          for a in r.iter() {
-              type_needs(cx, use_repr, *a);
-          }
-      }
-      ExprMethodCall(callee_id, rcvr, _, _, _, _) => {
-        let base_ty = ty::node_id_to_type(cx.ccx.tcx, rcvr.id);
-        type_needs(cx, use_repr, ty::type_autoderef(cx.ccx.tcx, base_ty));
-
-        let r = ty::ty_fn_args(ty::node_id_to_type(cx.ccx.tcx, callee_id));
-        for a in r.iter() {
-            type_needs(cx, use_repr, *a);
-        }
-        mark_for_method_call(cx, e.id, callee_id);
-      }
-
-      ExprInlineAsm(ref ia) => {
-        for &(_, input) in ia.inputs.iter() {
-          node_type_needs(cx, use_repr, input.id);
-        }
-        for &(_, out) in ia.outputs.iter() {
-          node_type_needs(cx, use_repr, out.id);
-        }
-      }
-
-      ExprParen(e) => mark_for_expr(cx, e),
-
-      ExprMatch(*) | ExprBlock(_) | ExprIf(*) | ExprWhile(*) |
-      ExprBreak(_) | ExprAgain(_) | ExprUnary(*) | ExprLit(_) |
-      ExprMac(_) | ExprAddrOf(*) | ExprRet(_) | ExprLoop(*) |
-      ExprDoBody(_) | ExprLogLevel => (),
-
-      ExprForLoop(*) => fail!("non-desugared expr_for_loop")
-    }
-}
-
-impl Visitor<()> for Context {
-
-    fn visit_expr(&mut self, e:@Expr, _: ()) {
-            visit::walk_expr(self, e, ());
-            mark_for_expr(self, e);
-    }
-
-    fn visit_local(&mut self, l:@Local, _:()) {
-            visit::walk_local(self, l, ());
-            node_type_needs(self, use_repr, l.id);
-    }
-
-    fn visit_pat(&mut self, p:@Pat, _: ()) {
-            visit::walk_pat(self, p, ());
-            node_type_needs(self, use_repr, p.id);
-    }
-
-   fn visit_block(&mut self, b:&Block, _: ()) {
-            visit::walk_block(self, b, ());
-            for e in b.expr.iter() {
-                node_type_needs(self, use_repr, e.id);
-            }
-    }
-
-    fn visit_item(&mut self, _:@item, _: ()) {
-        // do nothing
-    }
-
-}
-
-pub fn handle_body(cx: &mut Context, body: &Block) {
-    cx.visit_block(body, ());
-}