1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Translation Item Collection
12 //! ===========================
14 //! This module is responsible for discovering all items that will contribute to
15 //! to code generation of the crate. The important part here is that it not only
16 //! needs to find syntax-level items (functions, structs, etc) but also all
17 //! their monomorphized instantiations. Every non-generic, non-const function
18 //! maps to one LLVM artifact. Every generic function can produce
19 //! from zero to N artifacts, depending on the sets of type arguments it
20 //! is instantiated with.
21 //! This also applies to generic items from other crates: A generic definition
22 //! in crate X might produce monomorphizations that are compiled into crate Y.
23 //! We also have to collect these here.
25 //! The following kinds of "translation items" are handled here:
33 //! The following things also result in LLVM artifacts, but are not collected
34 //! here, since we instantiate them locally on demand when needed in a given
44 //! Let's define some terms first:
46 //! - A "translation item" is something that results in a function or global in
47 //! the LLVM IR of a codegen unit. Translation items do not stand on their
48 //! own, they can reference other translation items. For example, if function
49 //! `foo()` calls function `bar()` then the translation item for `foo()`
50 //! references the translation item for function `bar()`. In general, the
51 //! definition for translation item A referencing a translation item B is that
52 //! the LLVM artifact produced for A references the LLVM artifact produced
55 //! - Translation items and the references between them for a directed graph,
56 //! where the translation items are the nodes and references form the edges.
57 //! Let's call this graph the "translation item graph".
59 //! - The translation item graph for a program contains all translation items
60 //! that are needed in order to produce the complete LLVM IR of the program.
62 //! The purpose of the algorithm implemented in this module is to build the
63 //! translation item graph for the current crate. It runs in two phases:
65 //! 1. Discover the roots of the graph by traversing the HIR of the crate.
66 //! 2. Starting from the roots, find neighboring nodes by inspecting the MIR
67 //! representation of the item corresponding to a given node, until no more
68 //! new nodes are found.
70 //! ### Discovering roots
72 //! The roots of the translation item graph correspond to the non-generic
73 //! syntactic items in the source code. We find them by walking the HIR of the
74 //! crate, and whenever we hit upon a function, method, or static item, we
75 //! create a translation item consisting of the items DefId and, since we only
76 //! consider non-generic items, an empty type-substitution set.
78 //! ### Finding neighbor nodes
79 //! Given a translation item node, we can discover neighbors by inspecting its
80 //! MIR. We walk the MIR and any time we hit upon something that signifies a
81 //! reference to another translation item, we have found a neighbor. Since the
82 //! translation item we are currently at is always monomorphic, we also know the
83 //! concrete type arguments of its neighbors, and so all neighbors again will be
84 //! monomorphic. The specific forms a reference to a neighboring node can take
85 //! in MIR are quite diverse. Here is an overview:
87 //! #### Calling Functions/Methods
88 //! The most obvious form of one translation item referencing another is a
89 //! function or method call (represented by a CALL terminator in MIR). But
90 //! calls are not the only thing that might introduce a reference between two
91 //! function translation items, and as we will see below, they are just a
92 //! specialized of the form described next, and consequently will don't get any
93 //! special treatment in the algorithm.
95 //! #### Taking a reference to a function or method
96 //! A function does not need to actually be called in order to be a neighbor of
97 //! another function. It suffices to just take a reference in order to introduce
98 //! an edge. Consider the following example:
101 //! fn print_val<T: Display>(x: T) {
102 //! println!("{}", x);
105 //! fn call_fn(f: &Fn(i32), x: i32) {
110 //! let print_i32 = print_val::<i32>;
111 //! call_fn(&print_i32, 0);
114 //! The MIR of none of these functions will contain an explicit call to
115 //! `print_val::<i32>`. Nonetheless, in order to translate this program, we need
116 //! an instance of this function. Thus, whenever we encounter a function or
117 //! method in operand position, we treat it as a neighbor of the current
118 //! translation item. Calls are just a special case of that.
121 //! In a way, closures are a simple case. Since every closure object needs to be
122 //! constructed somewhere, we can reliably discover them by observing
123 //! `RValue::Aggregate` expressions with `AggregateKind::Closure`. This is also
124 //! true for closures inlined from other crates.
127 //! Drop glue translation items are introduced by MIR drop-statements. The
128 //! generated translation item will again have drop-glue item neighbors if the
129 //! type to be dropped contains nested values that also need to be dropped. It
130 //! might also have a function item neighbor for the explicit `Drop::drop`
131 //! implementation of its type.
133 //! #### Unsizing Casts
134 //! A subtle way of introducing neighbor edges is by casting to a trait object.
135 //! Since the resulting fat-pointer contains a reference to a vtable, we need to
136 //! instantiate all object-save methods of the trait, as we need to store
137 //! pointers to these functions even if they never get called anywhere. This can
138 //! be seen as a special case of taking a function reference.
141 //! Since `Box` expression have special compiler support, no explicit calls to
142 //! `exchange_malloc()` and `exchange_free()` may show up in MIR, even if the
143 //! compiler will generate them. We have to observe `Rvalue::Box` expressions
144 //! and Box-typed drop-statements for that purpose.
147 //! Interaction with Cross-Crate Inlining
148 //! -------------------------------------
149 //! The binary of a crate will not only contain machine code for the items
150 //! defined in the source code of that crate. It will also contain monomorphic
151 //! instantiations of any extern generic functions and of functions marked with
153 //! The collection algorithm handles this more or less transparently. If it is
154 //! about to create a translation item for something with an external `DefId`,
155 //! it will take a look if the MIR for that item is available, and if so just
156 //! proceed normally. If the MIR is not available, it assumes that that item is
157 //! just linked to and no node is created; which is exactly what we want, since
158 //! no machine code should be generated in the current crate for such an item.
160 //! Eager and Lazy Collection Mode
161 //! ------------------------------
162 //! Translation item collection can be performed in one of two modes:
164 //! - Lazy mode means that items will only be instantiated when actually
165 //! referenced. The goal is to produce the least amount of machine code
168 //! - Eager mode is meant to be used in conjunction with incremental compilation
169 //! where a stable set of translation items is more important than a minimal
170 //! one. Thus, eager mode will instantiate drop-glue for every drop-able type
171 //! in the crate, even of no drop call for that type exists (yet). It will
172 //! also instantiate default implementations of trait methods, something that
173 //! otherwise is only done on demand.
178 //! Some things are not yet fully implemented in the current version of this
181 //! ### Initializers of Constants and Statics
182 //! Since no MIR is constructed yet for initializer expressions of constants and
183 //! statics we cannot inspect these properly.
186 //! Ideally, no translation item should be generated for const fns unless there
187 //! is a call to them that cannot be evaluated at compile time. At the moment
188 //! this is not implemented however: a translation item will be produced
189 //! regardless of whether it is actually needed or not.
191 use rustc_front
::hir
;
192 use rustc_front
::intravisit
as hir_visit
;
194 use rustc
::front
::map
as hir_map
;
195 use rustc
::middle
::def_id
::DefId
;
196 use rustc
::middle
::lang_items
::{ExchangeFreeFnLangItem, ExchangeMallocFnLangItem}
;
197 use rustc
::middle
::{ty, traits}
;
198 use rustc
::middle
::subst
::{self, Substs, Subst}
;
199 use rustc
::middle
::ty
::adjustment
::CustomCoerceUnsized
;
200 use rustc
::middle
::ty
::fold
::TypeFoldable
;
201 use rustc
::mir
::repr
as mir
;
202 use rustc
::mir
::visit
as mir_visit
;
203 use rustc
::mir
::visit
::Visitor
as MirVisitor
;
205 use syntax
::ast
::{self, NodeId}
;
206 use syntax
::codemap
::DUMMY_SP
;
208 use syntax
::parse
::token
;
210 use trans
::base
::custom_coerce_unsize_info
;
211 use trans
::context
::CrateContext
;
212 use trans
::common
::{fulfill_obligation
, normalize_and_test_predicates
,
216 use trans
::monomorphize
;
217 use util
::nodemap
::{FnvHashSet, FnvHashMap, DefIdMap}
;
219 use std
::hash
::{Hash, Hasher}
;
222 #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
223 pub enum TransItemCollectionMode
{
228 #[derive(Eq, Clone, Copy, Debug)]
229 pub enum TransItem
<'tcx
> {
230 DropGlue(ty
::Ty
<'tcx
>),
233 substs
: &'tcx Substs
<'tcx
>
238 impl<'tcx
> Hash
for TransItem
<'tcx
> {
239 fn hash
<H
: Hasher
>(&self, s
: &mut H
) {
241 TransItem
::DropGlue(t
) => {
245 TransItem
::Fn { def_id, substs }
=> {
248 (substs
as *const Substs
<'tcx
> as usize).hash(s
);
250 TransItem
::Static(node_id
) => {
258 impl<'tcx
> PartialEq
for TransItem
<'tcx
> {
259 fn eq(&self, other
: &Self) -> bool
{
260 match (*self, *other
) {
261 (TransItem
::DropGlue(t1
), TransItem
::DropGlue(t2
)) => t1
== t2
,
262 (TransItem
::Fn { def_id: def_id1, substs: substs1 }
,
263 TransItem
::Fn { def_id: def_id2, substs: substs2 }
) => {
264 def_id1
== def_id2
&& substs1
== substs2
266 (TransItem
::Static(node_id1
), TransItem
::Static(node_id2
)) => {
274 pub fn collect_crate_translation_items
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
275 mode
: TransItemCollectionMode
)
276 -> FnvHashSet
<TransItem
<'tcx
>> {
277 // We are not tracking dependencies of this pass as it has to be re-executed
278 // every time no matter what.
279 ccx
.tcx().dep_graph
.with_ignore(|| {
280 let roots
= collect_roots(ccx
, mode
);
282 debug
!("Building translation item graph, beginning at roots");
283 let mut visited
= FnvHashSet();
284 let mut recursion_depths
= DefIdMap();
285 let mut mir_cache
= DefIdMap();
288 collect_items_rec(ccx
,
291 &mut recursion_depths
,
299 // Find all non-generic items by walking the HIR. These items serve as roots to
300 // start monomorphizing from.
301 fn collect_roots
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
302 mode
: TransItemCollectionMode
)
303 -> Vec
<TransItem
<'tcx
>> {
304 debug
!("Collecting roots");
305 let mut roots
= Vec
::new();
308 let mut visitor
= RootCollector
{
312 enclosing_item
: None
,
313 trans_empty_substs
: ccx
.tcx().mk_substs(Substs
::trans_empty()),
316 ccx
.tcx().map
.krate().visit_all_items(&mut visitor
);
323 enum CachedMir
<'mir
, 'tcx
: 'mir
> {
324 Ref(&'mir mir
::Mir
<'tcx
>),
325 Owned(Rc
<mir
::Mir
<'tcx
>>)
328 impl<'mir
, 'tcx
: 'mir
> CachedMir
<'mir
, 'tcx
> {
329 fn get_ref
<'a
>(&'a
self) -> &'a mir
::Mir
<'tcx
> {
331 CachedMir
::Ref(r
) => r
,
332 CachedMir
::Owned(ref rc
) => &rc
,
337 // Collect all monomorphized translation items reachable from `starting_point`
338 fn collect_items_rec
<'a
, 'tcx
: 'a
>(ccx
: &CrateContext
<'a
, 'tcx
>,
339 starting_point
: TransItem
<'tcx
>,
340 visited
: &mut FnvHashSet
<TransItem
<'tcx
>>,
341 recursion_depths
: &mut DefIdMap
<usize>,
342 mir_cache
: &mut DefIdMap
<CachedMir
<'a
, 'tcx
>>) {
343 if !visited
.insert(starting_point
.clone()) {
344 // We've been here already, no need to search again.
347 debug
!("BEGIN collect_items_rec({})", starting_point
.to_string(ccx
));
349 let mut neighbors
= Vec
::new();
350 let recursion_depth_reset
;
352 match starting_point
{
353 TransItem
::DropGlue(t
) => {
354 find_drop_glue_neighbors(ccx
, t
, &mut neighbors
);
355 recursion_depth_reset
= None
;
357 TransItem
::Static(_
) => {
358 recursion_depth_reset
= None
;
360 TransItem
::Fn { def_id, substs: ref param_substs }
=> {
361 // Keep track of the monomorphization recursion depth
362 recursion_depth_reset
= Some(check_recursion_limit(ccx
,
366 // Scan the MIR in order to find function calls, closures, and
368 let mir
= load_mir(ccx
, def_id
, mir_cache
);
370 let mut visitor
= MirNeighborCollector
{
373 output
: &mut neighbors
,
374 param_substs
: param_substs
377 visitor
.visit_mir(mir
.get_ref());
381 for neighbour
in neighbors
{
382 collect_items_rec(ccx
, neighbour
, visited
, recursion_depths
, mir_cache
);
385 if let Some((def_id
, depth
)) = recursion_depth_reset
{
386 recursion_depths
.insert(def_id
, depth
);
389 debug
!("END collect_items_rec({})", starting_point
.to_string(ccx
));
392 fn load_mir
<'a
, 'tcx
: 'a
>(ccx
: &CrateContext
<'a
, 'tcx
>,
394 mir_cache
: &mut DefIdMap
<CachedMir
<'a
, 'tcx
>>)
395 -> CachedMir
<'a
, 'tcx
> {
396 let mir_not_found_error_message
= || {
397 format
!("Could not find MIR for function: {}",
398 ccx
.tcx().item_path_str(def_id
))
401 if def_id
.is_local() {
402 let node_id
= ccx
.tcx().map
.as_local_node_id(def_id
).unwrap();
403 let mir_opt
= ccx
.mir_map().map
.get(&node_id
);
404 let mir
= errors
::expect(ccx
.sess().diagnostic(),
406 mir_not_found_error_message
);
409 if let Some(mir
) = mir_cache
.get(&def_id
) {
413 let mir_opt
= ccx
.sess().cstore
.maybe_get_item_mir(ccx
.tcx(), def_id
);
414 let mir
= errors
::expect(ccx
.sess().diagnostic(),
416 mir_not_found_error_message
);
417 let cached
= CachedMir
::Owned(Rc
::new(mir
));
418 mir_cache
.insert(def_id
, cached
.clone());
423 fn check_recursion_limit
<'a
, 'tcx
: 'a
>(ccx
: &CrateContext
<'a
, 'tcx
>,
425 recursion_depths
: &mut DefIdMap
<usize>)
427 let recursion_depth
= recursion_depths
.get(&def_id
)
430 debug
!(" => recursion depth={}", recursion_depth
);
432 // Code that needs to instantiate the same function recursively
433 // more than the recursion limit is assumed to be causing an
434 // infinite expansion.
435 if recursion_depth
> ccx
.sess().recursion_limit
.get() {
436 if let Some(node_id
) = ccx
.tcx().map
.as_local_node_id(def_id
) {
437 ccx
.sess().span_fatal(ccx
.tcx().map
.span(node_id
),
438 "reached the recursion limit during monomorphization");
440 let error
= format
!("reached the recursion limit during \
441 monomorphization of '{}'",
442 ccx
.tcx().item_path_str(def_id
));
443 ccx
.sess().fatal(&error
[..]);
447 recursion_depths
.insert(def_id
, recursion_depth
+ 1);
449 (def_id
, recursion_depth
)
452 struct MirNeighborCollector
<'a
, 'tcx
: 'a
> {
453 ccx
: &'a CrateContext
<'a
, 'tcx
>,
454 mir
: &'a mir
::Mir
<'tcx
>,
455 output
: &'a
mut Vec
<TransItem
<'tcx
>>,
456 param_substs
: &'tcx Substs
<'tcx
>
459 impl<'a
, 'tcx
> MirVisitor
<'tcx
> for MirNeighborCollector
<'a
, 'tcx
> {
461 fn visit_rvalue(&mut self, rvalue
: &mir
::Rvalue
<'tcx
>) {
462 debug
!("visiting rvalue {:?}", *rvalue
);
465 mir
::Rvalue
::Aggregate(mir
::AggregateKind
::Closure(def_id
,
467 assert
!(can_have_local_instance(self.ccx
, def_id
));
468 let trans_item
= create_fn_trans_item(self.ccx
,
472 self.output
.push(trans_item
);
474 // When doing an cast from a regular pointer to a fat pointer, we
475 // have to instantiate all methods of the trait being cast to, so we
476 // can build the appropriate vtable.
477 mir
::Rvalue
::Cast(mir
::CastKind
::Unsize
, ref operand
, target_ty
) => {
478 let target_ty
= monomorphize
::apply_param_substs(self.ccx
.tcx(),
481 let source_ty
= self.mir
.operand_ty(self.ccx
.tcx(), operand
);
482 let source_ty
= monomorphize
::apply_param_substs(self.ccx
.tcx(),
485 let (source_ty
, target_ty
) = find_vtable_types_for_unsizing(self.ccx
,
488 // This could also be a different Unsize instruction, like
489 // from a fixed sized array to a slice. But we are only
490 // interested in things that produce a vtable.
491 if target_ty
.is_trait() && !source_ty
.is_trait() {
492 create_trans_items_for_vtable_methods(self.ccx
,
498 mir
::Rvalue
::Box(_
) => {
499 let exchange_malloc_fn_def_id
=
503 .require(ExchangeMallocFnLangItem
)
504 .unwrap_or_else(|e
| self.ccx
.sess().fatal(&e
));
506 assert
!(can_have_local_instance(self.ccx
, exchange_malloc_fn_def_id
));
507 let exchange_malloc_fn_trans_item
=
508 create_fn_trans_item(self.ccx
,
509 exchange_malloc_fn_def_id
,
510 &Substs
::trans_empty(),
513 self.output
.push(exchange_malloc_fn_trans_item
);
515 _
=> { /* not interesting */ }
518 self.super_rvalue(rvalue
);
521 fn visit_lvalue(&mut self,
522 lvalue
: &mir
::Lvalue
<'tcx
>,
523 context
: mir_visit
::LvalueContext
) {
524 debug
!("visiting lvalue {:?}", *lvalue
);
526 if let mir_visit
::LvalueContext
::Drop
= context
{
527 let ty
= self.mir
.lvalue_ty(self.ccx
.tcx(), lvalue
)
528 .to_ty(self.ccx
.tcx());
530 let ty
= monomorphize
::apply_param_substs(self.ccx
.tcx(),
533 let ty
= self.ccx
.tcx().erase_regions(&ty
);
534 let ty
= glue
::get_drop_glue_type(self.ccx
, ty
);
535 self.output
.push(TransItem
::DropGlue(ty
));
538 self.super_lvalue(lvalue
, context
);
541 fn visit_operand(&mut self, operand
: &mir
::Operand
<'tcx
>) {
542 debug
!("visiting operand {:?}", *operand
);
544 let callee
= match *operand
{
545 mir
::Operand
::Constant(mir
::Constant
{
546 literal
: mir
::Literal
::Item
{
552 }) if is_function_or_method(kind
) => Some((def_id
, substs
)),
556 if let Some((callee_def_id
, callee_substs
)) = callee
{
557 debug
!(" => operand is callable");
559 // `callee_def_id` might refer to a trait method instead of a
560 // concrete implementation, so we have to find the actual
561 // implementation. For example, the call might look like
563 // std::cmp::partial_cmp(0i32, 1i32)
565 // Calling do_static_dispatch() here will map the def_id of
566 // `std::cmp::partial_cmp` to the def_id of `i32::partial_cmp<i32>`
567 let dispatched
= do_static_dispatch(self.ccx
,
572 if let Some((callee_def_id
, callee_substs
)) = dispatched
{
573 // if we have a concrete impl (which we might not have
574 // in the case of something compiler generated like an
575 // object shim or a closure that is handled differently),
576 // we check if the callee is something that will actually
577 // result in a translation item ...
578 if can_result_in_trans_item(self.ccx
, callee_def_id
) {
579 // ... and create one if it does.
580 let trans_item
= create_fn_trans_item(self.ccx
,
584 self.output
.push(trans_item
);
589 self.super_operand(operand
);
591 fn is_function_or_method(item_kind
: mir
::ItemKind
) -> bool
{
593 mir
::ItemKind
::Constant
=> false,
594 mir
::ItemKind
::Function
|
595 mir
::ItemKind
::Method
=> true
599 fn can_result_in_trans_item
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
602 if !match ccx
.tcx().lookup_item_type(def_id
).ty
.sty
{
603 ty
::TyBareFn(Some(def_id
), _
) => {
604 // Some constructors also have type TyBareFn but they are
605 // always instantiated inline and don't result in
607 match ccx
.tcx().map
.get_if_local(def_id
) {
608 Some(hir_map
::NodeVariant(_
)) |
609 Some(hir_map
::NodeStructCtor(_
)) => false,
612 ccx
.sess().cstore
.variant_kind(def_id
).is_none()
616 ty
::TyClosure(..) => true,
622 can_have_local_instance(ccx
, def_id
)
627 fn can_have_local_instance
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
630 // Take a look if we have the definition available. If not, we
631 // will not emit code for this item in the local crate, and thus
632 // don't create a translation item for it.
633 def_id
.is_local() || ccx
.sess().cstore
.is_item_mir_available(def_id
)
636 fn find_drop_glue_neighbors
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
638 output
: &mut Vec
<TransItem
<'tcx
>>)
640 debug
!("find_drop_glue_neighbors: {}", type_to_string(ccx
, ty
));
642 // Make sure the exchange_free_fn() lang-item gets translated if
643 // there is a boxed value.
644 if let ty
::TyBox(_
) = ty
.sty
{
645 let exchange_free_fn_def_id
= ccx
.tcx()
647 .require(ExchangeFreeFnLangItem
)
648 .unwrap_or_else(|e
| ccx
.sess().fatal(&e
));
650 assert
!(can_have_local_instance(ccx
, exchange_free_fn_def_id
));
651 let exchange_free_fn_trans_item
=
652 create_fn_trans_item(ccx
,
653 exchange_free_fn_def_id
,
654 &Substs
::trans_empty(),
655 &Substs
::trans_empty());
657 output
.push(exchange_free_fn_trans_item
);
660 // If the type implements Drop, also add a translation item for the
661 // monomorphized Drop::drop() implementation.
662 let destructor_did
= match ty
.sty
{
663 ty
::TyStruct(def
, _
) |
664 ty
::TyEnum(def
, _
) => def
.destructor(),
668 if let Some(destructor_did
) = destructor_did
{
669 use rustc
::middle
::ty
::ToPolyTraitRef
;
671 let drop_trait_def_id
= ccx
.tcx()
676 let self_type_substs
= ccx
.tcx().mk_substs(
677 Substs
::trans_empty().with_self_ty(ty
));
679 let trait_ref
= ty
::TraitRef
{
680 def_id
: drop_trait_def_id
,
681 substs
: self_type_substs
,
682 }.to_poly_trait_ref();
684 let substs
= match fulfill_obligation(ccx
, DUMMY_SP
, trait_ref
) {
685 traits
::VtableImpl(data
) => data
.substs
,
689 if can_have_local_instance(ccx
, destructor_did
) {
690 let trans_item
= create_fn_trans_item(ccx
,
692 ccx
.tcx().mk_substs(substs
),
693 &Substs
::trans_empty());
694 output
.push(trans_item
);
698 // Finally add the types of nested values
713 ty
::TyStruct(ref adt_def
, substs
) |
714 ty
::TyEnum(ref adt_def
, substs
) => {
715 for field
in adt_def
.all_fields() {
716 let field_type
= monomorphize
::apply_param_substs(ccx
.tcx(),
718 &field
.unsubst_ty());
719 let field_type
= glue
::get_drop_glue_type(ccx
, field_type
);
721 if glue
::type_needs_drop(ccx
.tcx(), field_type
) {
722 output
.push(TransItem
::DropGlue(field_type
));
726 ty
::TyClosure(_
, ref substs
) => {
727 for upvar_ty
in &substs
.upvar_tys
{
728 let upvar_ty
= glue
::get_drop_glue_type(ccx
, upvar_ty
);
729 if glue
::type_needs_drop(ccx
.tcx(), upvar_ty
) {
730 output
.push(TransItem
::DropGlue(upvar_ty
));
734 ty
::TyBox(inner_type
) |
735 ty
::TyArray(inner_type
, _
) => {
736 let inner_type
= glue
::get_drop_glue_type(ccx
, inner_type
);
737 if glue
::type_needs_drop(ccx
.tcx(), inner_type
) {
738 output
.push(TransItem
::DropGlue(inner_type
));
741 ty
::TyTuple(ref args
) => {
743 let arg
= glue
::get_drop_glue_type(ccx
, arg
);
744 if glue
::type_needs_drop(ccx
.tcx(), arg
) {
745 output
.push(TransItem
::DropGlue(arg
));
749 ty
::TyProjection(_
) |
753 ccx
.sess().bug("encountered unexpected type");
758 fn do_static_dispatch
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
760 fn_substs
: &'tcx Substs
<'tcx
>,
761 param_substs
: &'tcx Substs
<'tcx
>)
762 -> Option
<(DefId
, &'tcx Substs
<'tcx
>)> {
763 debug
!("do_static_dispatch(fn_def_id={}, fn_substs={:?}, param_substs={:?})",
764 def_id_to_string(ccx
, fn_def_id
, None
),
768 let is_trait_method
= ccx
.tcx().trait_of_item(fn_def_id
).is_some();
771 match ccx
.tcx().impl_or_trait_item(fn_def_id
) {
772 ty
::MethodTraitItem(ref method
) => {
773 match method
.container
{
774 ty
::TraitContainer(trait_def_id
) => {
775 debug
!(" => trait method, attempting to find impl");
776 do_static_trait_method_dispatch(ccx
,
782 ty
::ImplContainer(_
) => {
783 // This is already a concrete implementation
784 debug
!(" => impl method");
785 Some((fn_def_id
, fn_substs
))
792 debug
!(" => regular function");
793 // The function is not part of an impl or trait, no dispatching
795 Some((fn_def_id
, fn_substs
))
799 // Given a trait-method and substitution information, find out the actual
800 // implementation of the trait method.
801 fn do_static_trait_method_dispatch
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
802 trait_method
: &ty
::Method
,
804 callee_substs
: &'tcx Substs
<'tcx
>,
805 param_substs
: &'tcx Substs
<'tcx
>)
806 -> Option
<(DefId
, &'tcx Substs
<'tcx
>)> {
808 debug
!("do_static_trait_method_dispatch(trait_method={}, \
810 callee_substs={:?}, \
812 def_id_to_string(ccx
, trait_method
.def_id
, None
),
813 def_id_to_string(ccx
, trait_id
, None
),
817 let rcvr_substs
= monomorphize
::apply_param_substs(tcx
,
821 let trait_ref
= ty
::Binder(rcvr_substs
.to_trait_ref(tcx
, trait_id
));
822 let vtbl
= fulfill_obligation(ccx
, DUMMY_SP
, trait_ref
);
824 // Now that we know which impl is being used, we can dispatch to
825 // the actual function:
827 traits
::VtableImpl(traits
::VtableImplData
{
828 impl_def_id
: impl_did
,
832 let callee_substs
= impl_substs
.with_method_from(&rcvr_substs
);
833 let impl_method
= tcx
.get_impl_method(impl_did
,
836 Some((impl_method
.method
.def_id
, tcx
.mk_substs(impl_method
.substs
)))
838 // If we have a closure or a function pointer, we will also encounter
839 // the concrete closure/function somewhere else (during closure or fn
840 // pointer construction). That's where we track those things.
841 traits
::VtableClosure(..) |
842 traits
::VtableFnPointer(..) |
843 traits
::VtableObject(..) => {
847 tcx
.sess
.bug(&format
!("static call to invalid vtable: {:?}", vtbl
))
852 /// For given pair of source and target type that occur in an unsizing coercion,
853 /// this function finds the pair of types that determines the vtable linking
856 /// For example, the source type might be `&SomeStruct` and the target type\
857 /// might be `&SomeTrait` in a cast like:
859 /// let src: &SomeStruct = ...;
860 /// let target = src as &SomeTrait;
862 /// Then the output of this function would be (SomeStruct, SomeTrait) since for
863 /// constructing the `target` fat-pointer we need the vtable for that pair.
865 /// Things can get more complicated though because there's also the case where
866 /// the unsized type occurs as a field:
869 /// struct ComplexStruct<T: ?Sized> {
876 /// In this case, if `T` is sized, `&ComplexStruct<T>` is a thin pointer. If `T`
877 /// is unsized, `&SomeStruct` is a fat pointer, and the vtable it points to is
878 /// for the pair of `T` (which is a trait) and the concrete type that `T` was
879 /// originally coerced from:
881 /// let src: &ComplexStruct<SomeStruct> = ...;
882 /// let target = src as &ComplexStruct<SomeTrait>;
884 /// Again, we want this `find_vtable_types_for_unsizing()` to provide the pair
885 /// `(SomeStruct, SomeTrait)`.
887 /// Finally, there is also the case of custom unsizing coercions, e.g. for
888 /// smart pointers such as `Rc` and `Arc`.
889 fn find_vtable_types_for_unsizing
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
890 source_ty
: ty
::Ty
<'tcx
>,
891 target_ty
: ty
::Ty
<'tcx
>)
892 -> (ty
::Ty
<'tcx
>, ty
::Ty
<'tcx
>) {
893 match (&source_ty
.sty
, &target_ty
.sty
) {
894 (&ty
::TyBox(a
), &ty
::TyBox(b
)) |
895 (&ty
::TyRef(_
, ty
::TypeAndMut { ty: a, .. }
),
896 &ty
::TyRef(_
, ty
::TypeAndMut { ty: b, .. }
)) |
897 (&ty
::TyRef(_
, ty
::TypeAndMut { ty: a, .. }
),
898 &ty
::TyRawPtr(ty
::TypeAndMut { ty: b, .. }
)) |
899 (&ty
::TyRawPtr(ty
::TypeAndMut { ty: a, .. }
),
900 &ty
::TyRawPtr(ty
::TypeAndMut { ty: b, .. }
)) => {
901 let (inner_source
, inner_target
) = (a
, b
);
903 if !type_is_sized(ccx
.tcx(), inner_source
) {
904 (inner_source
, inner_target
)
906 ccx
.tcx().struct_lockstep_tails(inner_source
, inner_target
)
910 (&ty
::TyStruct(source_adt_def
, source_substs
),
911 &ty
::TyStruct(target_adt_def
, target_substs
)) => {
912 assert_eq
!(source_adt_def
, target_adt_def
);
914 let kind
= custom_coerce_unsize_info(ccx
, source_ty
, target_ty
);
916 let coerce_index
= match kind
{
917 CustomCoerceUnsized
::Struct(i
) => i
920 let source_fields
= &source_adt_def
.struct_variant().fields
;
921 let target_fields
= &target_adt_def
.struct_variant().fields
;
923 assert
!(coerce_index
< source_fields
.len() &&
924 source_fields
.len() == target_fields
.len());
926 find_vtable_types_for_unsizing(ccx
,
927 source_fields
[coerce_index
].ty(ccx
.tcx(),
929 target_fields
[coerce_index
].ty(ccx
.tcx(),
933 .bug(&format
!("find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}",
939 fn create_fn_trans_item
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
941 fn_substs
: &Substs
<'tcx
>,
942 param_substs
: &Substs
<'tcx
>)
945 debug
!("create_fn_trans_item(def_id={}, fn_substs={:?}, param_substs={:?})",
946 def_id_to_string(ccx
, def_id
, None
),
950 // We only get here, if fn_def_id either designates a local item or
951 // an inlineable external item. Non-inlineable external items are
952 // ignored because we don't want to generate any code for them.
953 let concrete_substs
= monomorphize
::apply_param_substs(ccx
.tcx(),
956 let concrete_substs
= ccx
.tcx().erase_regions(&concrete_substs
);
958 let trans_item
= TransItem
::Fn
{
960 substs
: ccx
.tcx().mk_substs(concrete_substs
),
966 /// Creates a `TransItem` for each method that is referenced by the vtable for
967 /// the given trait/impl pair.
968 fn create_trans_items_for_vtable_methods
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
969 trait_ty
: ty
::Ty
<'tcx
>,
970 impl_ty
: ty
::Ty
<'tcx
>,
971 output
: &mut Vec
<TransItem
<'tcx
>>) {
972 assert
!(!trait_ty
.needs_subst() && !impl_ty
.needs_subst());
974 if let ty
::TyTrait(ref trait_ty
) = trait_ty
.sty
{
975 let poly_trait_ref
= trait_ty
.principal_trait_ref_with_self_ty(ccx
.tcx(),
978 // Walk all methods of the trait, including those of its supertraits
979 for trait_ref
in traits
::supertraits(ccx
.tcx(), poly_trait_ref
) {
980 let vtable
= fulfill_obligation(ccx
, DUMMY_SP
, trait_ref
);
983 traits
::VtableImplData
{
987 let items
= meth
::get_vtable_methods(ccx
, impl_def_id
, substs
)
989 // filter out None values
990 .filter_map(|opt_impl_method
| opt_impl_method
)
991 // create translation items
992 .filter_map(|impl_method
| {
993 if can_have_local_instance(ccx
, impl_method
.method
.def_id
) {
994 let substs
= ccx
.tcx().mk_substs(impl_method
.substs
);
995 Some(create_fn_trans_item(ccx
,
996 impl_method
.method
.def_id
,
998 &Substs
::trans_empty()))
1003 .collect
::<Vec
<_
>>();
1005 output
.extend(items
.into_iter());
1013 //=-----------------------------------------------------------------------------
1015 //=-----------------------------------------------------------------------------
1017 struct RootCollector
<'b
, 'a
: 'b
, 'tcx
: 'a
+ 'b
> {
1018 ccx
: &'b CrateContext
<'a
, 'tcx
>,
1019 mode
: TransItemCollectionMode
,
1020 output
: &'b
mut Vec
<TransItem
<'tcx
>>,
1021 enclosing_item
: Option
<&'tcx hir
::Item
>,
1022 trans_empty_substs
: &'tcx Substs
<'tcx
>
1025 impl<'b
, 'a
, 'v
> hir_visit
::Visitor
<'v
> for RootCollector
<'b
, 'a
, 'v
> {
1026 fn visit_item(&mut self, item
: &'v hir
::Item
) {
1027 let old_enclosing_item
= self.enclosing_item
;
1028 self.enclosing_item
= Some(item
);
1031 hir
::ItemExternCrate(..) |
1033 hir
::ItemForeignMod(..) |
1035 hir
::ItemDefaultImpl(..) |
1036 hir
::ItemTrait(..) |
1037 hir
::ItemConst(..) |
1038 hir
::ItemMod(..) => {
1039 // Nothing to do, just keep recursing...
1042 hir
::ItemImpl(..) => {
1043 if self.mode
== TransItemCollectionMode
::Eager
{
1044 create_trans_items_for_default_impls(self.ccx
,
1046 self.trans_empty_substs
,
1051 hir
::ItemEnum(_
, ref generics
) |
1052 hir
::ItemStruct(_
, ref generics
) => {
1053 if !generics
.is_parameterized() {
1055 let tables
= self.ccx
.tcx().tables
.borrow();
1056 tables
.node_types
[&item
.id
]
1059 if self.mode
== TransItemCollectionMode
::Eager
{
1060 debug
!("RootCollector: ADT drop-glue for {}",
1061 def_id_to_string(self.ccx
,
1062 self.ccx
.tcx().map
.local_def_id(item
.id
),
1065 let ty
= glue
::get_drop_glue_type(self.ccx
, ty
);
1066 self.output
.push(TransItem
::DropGlue(ty
));
1070 hir
::ItemStatic(..) => {
1071 debug
!("RootCollector: ItemStatic({})",
1072 def_id_to_string(self.ccx
,
1073 self.ccx
.tcx().map
.local_def_id(item
.id
),
1075 self.output
.push(TransItem
::Static(item
.id
));
1077 hir
::ItemFn(_
, _
, constness
, _
, ref generics
, _
) => {
1078 if !generics
.is_type_parameterized() &&
1079 constness
== hir
::Constness
::NotConst
{
1080 let def_id
= self.ccx
.tcx().map
.local_def_id(item
.id
);
1082 debug
!("RootCollector: ItemFn({})",
1083 def_id_to_string(self.ccx
, def_id
, None
));
1085 self.output
.push(TransItem
::Fn
{
1087 substs
: self.trans_empty_substs
1093 hir_visit
::walk_item(self, item
);
1094 self.enclosing_item
= old_enclosing_item
;
1097 fn visit_impl_item(&mut self, ii
: &'v hir
::ImplItem
) {
1099 hir
::ImplItemKind
::Method(hir
::MethodSig
{
1103 }, _
) if constness
== hir
::Constness
::NotConst
=> {
1104 let hir_map
= &self.ccx
.tcx().map
;
1105 let parent_node_id
= hir_map
.get_parent_node(ii
.id
);
1106 let is_impl_generic
= match hir_map
.expect_item(parent_node_id
) {
1108 node
: hir
::ItemImpl(_
, _
, ref generics
, _
, _
, _
),
1111 generics
.is_type_parameterized()
1118 if !generics
.is_type_parameterized() && !is_impl_generic
{
1119 let def_id
= self.ccx
.tcx().map
.local_def_id(ii
.id
);
1121 debug
!("RootCollector: MethodImplItem({})",
1122 def_id_to_string(self.ccx
, def_id
, None
));
1124 self.output
.push(TransItem
::Fn
{
1126 substs
: self.trans_empty_substs
1130 _
=> { /* Nothing to do here */ }
1133 hir_visit
::walk_impl_item(self, ii
)
1137 fn create_trans_items_for_default_impls
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
1138 item
: &'tcx hir
::Item
,
1139 trans_empty_substs
: &'tcx Substs
<'tcx
>,
1140 output
: &mut Vec
<TransItem
<'tcx
>>) {
1148 if generics
.is_type_parameterized() {
1152 let tcx
= ccx
.tcx();
1153 let impl_def_id
= tcx
.map
.local_def_id(item
.id
);
1155 debug
!("create_trans_items_for_default_impls(item={})",
1156 def_id_to_string(ccx
, impl_def_id
, None
));
1158 if let Some(trait_ref
) = tcx
.impl_trait_ref(impl_def_id
) {
1159 let default_impls
= tcx
.provided_trait_methods(trait_ref
.def_id
);
1160 let callee_substs
= tcx
.mk_substs(tcx
.erase_regions(trait_ref
.substs
));
1161 let overridden_methods
: FnvHashSet
<_
> = items
.iter()
1162 .map(|item
| item
.name
)
1164 for default_impl
in default_impls
{
1165 if overridden_methods
.contains(&default_impl
.name
) {
1169 if default_impl
.generics
.has_type_params(subst
::FnSpace
) {
1173 // The substitutions we have are on the impl, so we grab
1174 // the method type from the impl to substitute into.
1175 let mth
= tcx
.get_impl_method(impl_def_id
,
1176 callee_substs
.clone(),
1179 assert
!(mth
.is_provided
);
1181 let predicates
= mth
.method
.predicates
.predicates
.subst(tcx
, &mth
.substs
);
1182 if !normalize_and_test_predicates(ccx
, predicates
.into_vec()) {
1186 if can_have_local_instance(ccx
, default_impl
.def_id
) {
1187 let item
= create_fn_trans_item(ccx
,
1188 default_impl
.def_id
,
1190 trans_empty_substs
);
1202 //=-----------------------------------------------------------------------------
1203 // TransItem String Keys
1204 //=-----------------------------------------------------------------------------
1206 // The code below allows for producing a unique string key for a trans item.
1207 // These keys are used by the handwritten auto-tests, so they need to be
1208 // predictable and human-readable.
1210 // Note: A lot of this could looks very similar to what's already in the
1211 // ppaux module. It would be good to refactor things so we only have one
1212 // parameterizable implementation for printing types.
1214 /// Same as `unique_type_name()` but with the result pushed onto the given
1215 /// `output` parameter.
1216 pub fn push_unique_type_name
<'a
, 'tcx
>(cx
: &CrateContext
<'a
, 'tcx
>,
1218 output
: &mut String
) {
1220 ty
::TyBool
=> output
.push_str("bool"),
1221 ty
::TyChar
=> output
.push_str("char"),
1222 ty
::TyStr
=> output
.push_str("str"),
1223 ty
::TyInt(ast
::IntTy
::Is
) => output
.push_str("isize"),
1224 ty
::TyInt(ast
::IntTy
::I8
) => output
.push_str("i8"),
1225 ty
::TyInt(ast
::IntTy
::I16
) => output
.push_str("i16"),
1226 ty
::TyInt(ast
::IntTy
::I32
) => output
.push_str("i32"),
1227 ty
::TyInt(ast
::IntTy
::I64
) => output
.push_str("i64"),
1228 ty
::TyUint(ast
::UintTy
::Us
) => output
.push_str("usize"),
1229 ty
::TyUint(ast
::UintTy
::U8
) => output
.push_str("u8"),
1230 ty
::TyUint(ast
::UintTy
::U16
) => output
.push_str("u16"),
1231 ty
::TyUint(ast
::UintTy
::U32
) => output
.push_str("u32"),
1232 ty
::TyUint(ast
::UintTy
::U64
) => output
.push_str("u64"),
1233 ty
::TyFloat(ast
::FloatTy
::F32
) => output
.push_str("f32"),
1234 ty
::TyFloat(ast
::FloatTy
::F64
) => output
.push_str("f64"),
1235 ty
::TyStruct(adt_def
, substs
) |
1236 ty
::TyEnum(adt_def
, substs
) => {
1237 push_item_name(cx
, adt_def
.did
, output
);
1238 push_type_params(cx
, substs
, &[], output
);
1240 ty
::TyTuple(ref component_types
) => {
1242 for &component_type
in component_types
{
1243 push_unique_type_name(cx
, component_type
, output
);
1244 output
.push_str(", ");
1246 if !component_types
.is_empty() {
1252 ty
::TyBox(inner_type
) => {
1253 output
.push_str("Box<");
1254 push_unique_type_name(cx
, inner_type
, output
);
1257 ty
::TyRawPtr(ty
::TypeAndMut { ty: inner_type, mutbl }
) => {
1260 hir
::MutImmutable
=> output
.push_str("const "),
1261 hir
::MutMutable
=> output
.push_str("mut "),
1264 push_unique_type_name(cx
, inner_type
, output
);
1266 ty
::TyRef(_
, ty
::TypeAndMut { ty: inner_type, mutbl }
) => {
1268 if mutbl
== hir
::MutMutable
{
1269 output
.push_str("mut ");
1272 push_unique_type_name(cx
, inner_type
, output
);
1274 ty
::TyArray(inner_type
, len
) => {
1276 push_unique_type_name(cx
, inner_type
, output
);
1277 output
.push_str(&format
!("; {}", len
));
1280 ty
::TySlice(inner_type
) => {
1282 push_unique_type_name(cx
, inner_type
, output
);
1285 ty
::TyTrait(ref trait_data
) => {
1286 push_item_name(cx
, trait_data
.principal
.skip_binder().def_id
, output
);
1287 push_type_params(cx
,
1288 &trait_data
.principal
.skip_binder().substs
,
1289 &trait_data
.bounds
.projection_bounds
,
1292 ty
::TyBareFn(_
, &ty
::BareFnTy{ unsafety, abi, ref sig }
) => {
1293 if unsafety
== hir
::Unsafety
::Unsafe
{
1294 output
.push_str("unsafe ");
1297 if abi
!= ::syntax
::abi
::Abi
::Rust
{
1298 output
.push_str("extern \"");
1299 output
.push_str(abi
.name());
1300 output
.push_str("\" ");
1303 output
.push_str("fn(");
1305 let sig
= cx
.tcx().erase_late_bound_regions(sig
);
1306 if !sig
.inputs
.is_empty() {
1307 for ¶meter_type
in &sig
.inputs
{
1308 push_unique_type_name(cx
, parameter_type
, output
);
1309 output
.push_str(", ");
1316 if !sig
.inputs
.is_empty() {
1317 output
.push_str(", ...");
1319 output
.push_str("...");
1326 ty
::FnConverging(result_type
) if result_type
.is_nil() => {}
1327 ty
::FnConverging(result_type
) => {
1328 output
.push_str(" -> ");
1329 push_unique_type_name(cx
, result_type
, output
);
1331 ty
::FnDiverging
=> {
1332 output
.push_str(" -> !");
1336 ty
::TyClosure(def_id
, ref closure_substs
) => {
1337 push_item_name(cx
, def_id
, output
);
1338 output
.push_str("{");
1339 output
.push_str(&format
!("{}:{}", def_id
.krate
, def_id
.index
.as_usize()));
1340 output
.push_str("}");
1341 push_type_params(cx
, closure_substs
.func_substs
, &[], output
);
1345 ty
::TyProjection(..) |
1347 cx
.sess().bug(&format
!("debuginfo: Trying to create type name for \
1348 unexpected type: {:?}", t
));
1353 fn push_item_name(ccx
: &CrateContext
,
1355 output
: &mut String
) {
1356 if def_id
.is_local() {
1357 let node_id
= ccx
.tcx().map
.as_local_node_id(def_id
).unwrap();
1358 let inlined_from
= ccx
.external_srcs()
1361 .map(|def_id
| *def_id
);
1363 if let Some(extern_def_id
) = inlined_from
{
1364 push_item_name(ccx
, extern_def_id
, output
);
1368 output
.push_str(&ccx
.link_meta().crate_name
);
1369 output
.push_str("::");
1372 for part
in ccx
.tcx().def_path(def_id
) {
1373 output
.push_str(&format
!("{}[{}]::",
1374 part
.data
.as_interned_str(),
1375 part
.disambiguator
));
1382 fn push_type_params
<'a
, 'tcx
>(cx
: &CrateContext
<'a
, 'tcx
>,
1383 substs
: &Substs
<'tcx
>,
1384 projections
: &[ty
::PolyProjectionPredicate
<'tcx
>],
1385 output
: &mut String
) {
1386 if substs
.types
.is_empty() && projections
.is_empty() {
1392 for &type_parameter
in &substs
.types
{
1393 push_unique_type_name(cx
, type_parameter
, output
);
1394 output
.push_str(", ");
1397 for projection
in projections
{
1398 let projection
= projection
.skip_binder();
1399 let name
= token
::get_ident_interner().get(projection
.projection_ty
.item_name
);
1400 output
.push_str(&name
[..]);
1401 output
.push_str("=");
1402 push_unique_type_name(cx
, projection
.ty
, output
);
1403 output
.push_str(", ");
1412 fn push_def_id_as_string
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
1414 substs
: Option
<&Substs
<'tcx
>>,
1415 output
: &mut String
) {
1416 push_item_name(ccx
, def_id
, output
);
1418 if let Some(substs
) = substs
{
1419 push_type_params(ccx
, substs
, &[], output
);
1423 fn def_id_to_string
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
1425 substs
: Option
<&Substs
<'tcx
>>)
1427 let mut output
= String
::new();
1428 push_def_id_as_string(ccx
, def_id
, substs
, &mut output
);
1432 fn type_to_string
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
1435 let mut output
= String
::new();
1436 push_unique_type_name(ccx
, ty
, &mut output
);
1440 impl<'tcx
> TransItem
<'tcx
> {
1442 pub fn to_string
<'a
>(&self, ccx
: &CrateContext
<'a
, 'tcx
>) -> String
{
1443 let hir_map
= &ccx
.tcx().map
;
1445 return match *self {
1446 TransItem
::DropGlue(t
) => {
1447 let mut s
= String
::with_capacity(32);
1448 s
.push_str("drop-glue ");
1449 push_unique_type_name(ccx
, t
, &mut s
);
1452 TransItem
::Fn { def_id, ref substs }
=> {
1453 to_string_internal(ccx
, "fn ", def_id
, Some(substs
))
1455 TransItem
::Static(node_id
) => {
1456 let def_id
= hir_map
.local_def_id(node_id
);
1457 to_string_internal(ccx
, "static ", def_id
, None
)
1461 fn to_string_internal
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
1464 substs
: Option
<&Substs
<'tcx
>>)
1466 let mut result
= String
::with_capacity(32);
1467 result
.push_str(prefix
);
1468 push_def_id_as_string(ccx
, def_id
, substs
, &mut result
);
1473 fn to_raw_string(&self) -> String
{
1475 TransItem
::DropGlue(t
) => {
1476 format
!("DropGlue({})", t
as *const _
as usize)
1478 TransItem
::Fn { def_id, substs }
=> {
1479 format
!("Fn({:?}, {})",
1481 substs
as *const _
as usize)
1483 TransItem
::Static(id
) => {
1484 format
!("Static({:?})", id
)
1490 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1491 pub enum TransItemState
{
1492 PredictedAndGenerated
,
1493 PredictedButNotGenerated
,
1494 NotPredictedButGenerated
,
1497 pub fn collecting_debug_information(ccx
: &CrateContext
) -> bool
{
1498 return cfg
!(debug_assertions
) &&
1499 ccx
.sess().opts
.debugging_opts
.print_trans_items
.is_some();
1502 pub fn print_collection_results
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>) {
1503 use std
::hash
::{Hash, SipHasher, Hasher}
;
1505 if !collecting_debug_information(ccx
) {
1509 fn hash
<T
: Hash
>(t
: &T
) -> u64 {
1510 let mut s
= SipHasher
::new();
1515 let trans_items
= ccx
.translation_items().borrow();
1518 // Check for duplicate item keys
1519 let mut item_keys
= FnvHashMap();
1521 for (item
, item_state
) in trans_items
.iter() {
1522 let k
= item
.to_string(&ccx
);
1524 if item_keys
.contains_key(&k
) {
1525 let prev
: (TransItem
, TransItemState
) = item_keys
[&k
];
1526 debug
!("DUPLICATE KEY: {}", k
);
1527 debug
!(" (1) {:?}, {:?}, hash: {}, raw: {}",
1531 prev
.0.to_raw_string());
1533 debug
!(" (2) {:?}, {:?}, hash: {}, raw: {}",
1537 item
.to_raw_string());
1539 item_keys
.insert(k
, (*item
, *item_state
));
1544 let mut predicted_but_not_generated
= FnvHashSet();
1545 let mut not_predicted_but_generated
= FnvHashSet();
1546 let mut predicted
= FnvHashSet();
1547 let mut generated
= FnvHashSet();
1549 for (item
, item_state
) in trans_items
.iter() {
1550 let item_key
= item
.to_string(&ccx
);
1553 TransItemState
::PredictedAndGenerated
=> {
1554 predicted
.insert(item_key
.clone());
1555 generated
.insert(item_key
);
1557 TransItemState
::PredictedButNotGenerated
=> {
1558 predicted_but_not_generated
.insert(item_key
.clone());
1559 predicted
.insert(item_key
);
1561 TransItemState
::NotPredictedButGenerated
=> {
1562 not_predicted_but_generated
.insert(item_key
.clone());
1563 generated
.insert(item_key
);
1568 debug
!("Total number of translation items predicted: {}", predicted
.len());
1569 debug
!("Total number of translation items generated: {}", generated
.len());
1570 debug
!("Total number of translation items predicted but not generated: {}",
1571 predicted_but_not_generated
.len());
1572 debug
!("Total number of translation items not predicted but generated: {}",
1573 not_predicted_but_generated
.len());
1575 if generated
.len() > 0 {
1576 debug
!("Failed to predict {}% of translation items",
1577 (100 * not_predicted_but_generated
.len()) / generated
.len());
1579 if generated
.len() > 0 {
1580 debug
!("Predict {}% too many translation items",
1581 (100 * predicted_but_not_generated
.len()) / generated
.len());
1585 debug
!("Not predicted but generated:");
1586 debug
!("============================");
1587 for item
in not_predicted_but_generated
{
1588 debug
!(" - {}", item
);
1592 debug
!("Predicted but not generated:");
1593 debug
!("============================");
1594 for item
in predicted_but_not_generated
{
1595 debug
!(" - {}", item
);