From c3e4e068416438e91e3e9809ee8553a764d8e26e Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Thu, 26 Sep 2013 16:54:15 -0400 Subject: [PATCH] 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 --- src/etc/monodebug.pl | 79 ---- src/etc/zsh/_rust | 1 - src/librustc/driver/driver.rs | 7 - src/librustc/driver/session.rs | 32 +- src/librustc/middle/trans/context.rs | 4 - src/librustc/middle/trans/meth.rs | 3 +- src/librustc/middle/trans/mod.rs | 1 - src/librustc/middle/trans/monomorphize.rs | 71 +--- src/librustc/middle/trans/type_use.rs | 449 ---------------------- 9 files changed, 21 insertions(+), 626 deletions(-) delete mode 100755 src/etc/monodebug.pl delete mode 100644 src/librustc/middle/trans/type_use.rs diff --git a/src/etc/monodebug.pl b/src/etc/monodebug.pl deleted file mode 100755 index a2d27591cad93..0000000000000 --- 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 3d0163d9e2593..a4b1bc629d1dc 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 5518dde0ee979..df3a40c228942 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 7f3f1f88a5244..19e866c70a3fe 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 134db45be43cb..36757374b0b06 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, monomorphizing: HashMap, - // Cache computed type parameter uses (see type_use.rs) - type_use_cache: HashMap, // 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 fd35d05f0fde7..ce4c1011e8064 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 008da7f7ff8f2..f55360213c6f6 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 ef055a52468c8..034320008cd14 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: ¶m_substs, - param_uses: Option<@~[type_use::type_uses]>) -> mono_id { + substs: ¶m_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 6ae196226d575..0000000000000 --- 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 or the MIT license -// , 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) { - 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, ()); -}