]>
Commit | Line | Data |
---|---|---|
7453a54e SL |
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. | |
4 | // | |
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. | |
10 | ||
11 | //! Translation Item Collection | |
12 | //! =========================== | |
13 | //! | |
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. | |
24 | //! | |
25 | //! The following kinds of "translation items" are handled here: | |
26 | //! | |
27 | //! - Functions | |
28 | //! - Methods | |
29 | //! - Closures | |
30 | //! - Statics | |
31 | //! - Drop glue | |
32 | //! | |
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 | |
35 | //! codegen unit: | |
36 | //! | |
37 | //! - Constants | |
38 | //! - Vtables | |
39 | //! - Object Shims | |
40 | //! | |
41 | //! | |
42 | //! General Algorithm | |
43 | //! ----------------- | |
44 | //! Let's define some terms first: | |
45 | //! | |
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 | |
53 | //! for B. | |
54 | //! | |
32a655c1 | 55 | //! - Translation items and the references between them form a directed graph, |
7453a54e SL |
56 | //! where the translation items are the nodes and references form the edges. |
57 | //! Let's call this graph the "translation item graph". | |
58 | //! | |
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. | |
61 | //! | |
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: | |
64 | //! | |
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. | |
69 | //! | |
70 | //! ### Discovering roots | |
71 | //! | |
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. | |
77 | //! | |
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: | |
86 | //! | |
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. | |
94 | //! | |
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: | |
99 | //! | |
100 | //! ```rust | |
101 | //! fn print_val<T: Display>(x: T) { | |
102 | //! println!("{}", x); | |
103 | //! } | |
104 | //! | |
105 | //! fn call_fn(f: &Fn(i32), x: i32) { | |
106 | //! f(x); | |
107 | //! } | |
108 | //! | |
109 | //! fn main() { | |
110 | //! let print_i32 = print_val::<i32>; | |
111 | //! call_fn(&print_i32, 0); | |
112 | //! } | |
113 | //! ``` | |
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. | |
119 | //! | |
120 | //! #### Closures | |
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. | |
125 | //! | |
126 | //! #### Drop glue | |
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. | |
132 | //! | |
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. | |
139 | //! | |
140 | //! #### Boxes | |
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. | |
145 | //! | |
146 | //! | |
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 | |
152 | //! #[inline]. | |
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 | |
9e0c209e | 156 | //! proceed normally. If the MIR is not available, it assumes that the item is |
7453a54e SL |
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. | |
159 | //! | |
160 | //! Eager and Lazy Collection Mode | |
161 | //! ------------------------------ | |
162 | //! Translation item collection can be performed in one of two modes: | |
163 | //! | |
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 | |
166 | //! possible. | |
167 | //! | |
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. | |
174 | //! | |
175 | //! | |
176 | //! Open Issues | |
177 | //! ----------- | |
178 | //! Some things are not yet fully implemented in the current version of this | |
179 | //! module. | |
180 | //! | |
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. | |
184 | //! | |
185 | //! ### Const Fns | |
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. | |
190 | ||
54a0048b | 191 | use rustc::hir; |
476ff2be | 192 | use rustc::hir::itemlikevisit::ItemLikeVisitor; |
7453a54e | 193 | |
54a0048b SL |
194 | use rustc::hir::map as hir_map; |
195 | use rustc::hir::def_id::DefId; | |
cc61c64b | 196 | use rustc::middle::lang_items::{ExchangeMallocFnLangItem}; |
54a0048b | 197 | use rustc::traits; |
041b39d2 | 198 | use rustc::ty::subst::Substs; |
a7813a04 | 199 | use rustc::ty::{self, TypeFoldable, TyCtxt}; |
54a0048b | 200 | use rustc::ty::adjustment::CustomCoerceUnsized; |
c30ab7b3 | 201 | use rustc::mir::{self, Location}; |
7453a54e SL |
202 | use rustc::mir::visit::Visitor as MirVisitor; |
203 | ||
a7813a04 | 204 | use context::SharedCrateContext; |
cc61c64b | 205 | use common::{def_ty, instance_ty}; |
54a0048b | 206 | use monomorphize::{self, Instance}; |
7cac9316 | 207 | use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap}; |
7453a54e | 208 | |
32a655c1 SL |
209 | use trans_item::{TransItem, DefPathBasedNames, InstantiationMode}; |
210 | ||
7453a54e SL |
211 | #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] |
212 | pub enum TransItemCollectionMode { | |
213 | Eager, | |
214 | Lazy | |
215 | } | |
216 | ||
a7813a04 XL |
217 | /// Maps every translation item to all translation items it references in its |
218 | /// body. | |
219 | pub struct InliningMap<'tcx> { | |
220 | // Maps a source translation item to a range of target translation items | |
221 | // that are potentially inlined by LLVM into the source. | |
222 | // The two numbers in the tuple are the start (inclusive) and | |
223 | // end index (exclusive) within the `targets` vecs. | |
476ff2be | 224 | index: FxHashMap<TransItem<'tcx>, (usize, usize)>, |
a7813a04 | 225 | targets: Vec<TransItem<'tcx>>, |
7453a54e SL |
226 | } |
227 | ||
a7813a04 XL |
228 | impl<'tcx> InliningMap<'tcx> { |
229 | ||
230 | fn new() -> InliningMap<'tcx> { | |
231 | InliningMap { | |
476ff2be | 232 | index: FxHashMap(), |
a7813a04 XL |
233 | targets: Vec::new(), |
234 | } | |
235 | } | |
236 | ||
237 | fn record_inlining_canditates<I>(&mut self, | |
238 | source: TransItem<'tcx>, | |
239 | targets: I) | |
240 | where I: Iterator<Item=TransItem<'tcx>> | |
241 | { | |
242 | assert!(!self.index.contains_key(&source)); | |
243 | ||
244 | let start_index = self.targets.len(); | |
245 | self.targets.extend(targets); | |
246 | let end_index = self.targets.len(); | |
247 | self.index.insert(source, (start_index, end_index)); | |
248 | } | |
249 | ||
250 | // Internally iterate over all items referenced by `source` which will be | |
251 | // made available for inlining. | |
252 | pub fn with_inlining_candidates<F>(&self, source: TransItem<'tcx>, mut f: F) | |
253 | where F: FnMut(TransItem<'tcx>) { | |
254 | if let Some(&(start_index, end_index)) = self.index.get(&source) | |
255 | { | |
256 | for candidate in &self.targets[start_index .. end_index] { | |
257 | f(*candidate) | |
7453a54e | 258 | } |
a7813a04 | 259 | } |
7453a54e SL |
260 | } |
261 | } | |
262 | ||
a7813a04 | 263 | pub fn collect_crate_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, |
7453a54e | 264 | mode: TransItemCollectionMode) |
476ff2be | 265 | -> (FxHashSet<TransItem<'tcx>>, |
a7813a04 | 266 | InliningMap<'tcx>) { |
7453a54e SL |
267 | // We are not tracking dependencies of this pass as it has to be re-executed |
268 | // every time no matter what. | |
a7813a04 XL |
269 | scx.tcx().dep_graph.with_ignore(|| { |
270 | let roots = collect_roots(scx, mode); | |
7453a54e SL |
271 | |
272 | debug!("Building translation item graph, beginning at roots"); | |
476ff2be | 273 | let mut visited = FxHashSet(); |
7453a54e | 274 | let mut recursion_depths = DefIdMap(); |
a7813a04 | 275 | let mut inlining_map = InliningMap::new(); |
7453a54e SL |
276 | |
277 | for root in roots { | |
a7813a04 XL |
278 | collect_items_rec(scx, |
279 | root, | |
280 | &mut visited, | |
281 | &mut recursion_depths, | |
282 | &mut inlining_map); | |
7453a54e SL |
283 | } |
284 | ||
a7813a04 | 285 | (visited, inlining_map) |
7453a54e SL |
286 | }) |
287 | } | |
288 | ||
289 | // Find all non-generic items by walking the HIR. These items serve as roots to | |
290 | // start monomorphizing from. | |
a7813a04 | 291 | fn collect_roots<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, |
7453a54e SL |
292 | mode: TransItemCollectionMode) |
293 | -> Vec<TransItem<'tcx>> { | |
294 | debug!("Collecting roots"); | |
295 | let mut roots = Vec::new(); | |
296 | ||
297 | { | |
298 | let mut visitor = RootCollector { | |
a7813a04 | 299 | scx: scx, |
7453a54e SL |
300 | mode: mode, |
301 | output: &mut roots, | |
7453a54e SL |
302 | }; |
303 | ||
32a655c1 | 304 | scx.tcx().hir.krate().visit_all_item_likes(&mut visitor); |
7453a54e SL |
305 | } |
306 | ||
041b39d2 XL |
307 | // We can only translate items that are instantiable - items all of |
308 | // whose predicates hold. Luckily, items that aren't instantiable | |
309 | // can't actually be used, so we can just skip translating them. | |
310 | roots.retain(|root| root.is_instantiable(scx.tcx())); | |
311 | ||
7453a54e SL |
312 | roots |
313 | } | |
314 | ||
7453a54e | 315 | // Collect all monomorphized translation items reachable from `starting_point` |
a7813a04 | 316 | fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, |
7453a54e | 317 | starting_point: TransItem<'tcx>, |
476ff2be | 318 | visited: &mut FxHashSet<TransItem<'tcx>>, |
a7813a04 XL |
319 | recursion_depths: &mut DefIdMap<usize>, |
320 | inlining_map: &mut InliningMap<'tcx>) { | |
7453a54e SL |
321 | if !visited.insert(starting_point.clone()) { |
322 | // We've been here already, no need to search again. | |
323 | return; | |
324 | } | |
a7813a04 | 325 | debug!("BEGIN collect_items_rec({})", starting_point.to_string(scx.tcx())); |
7453a54e SL |
326 | |
327 | let mut neighbors = Vec::new(); | |
328 | let recursion_depth_reset; | |
329 | ||
330 | match starting_point { | |
a7813a04 | 331 | TransItem::Static(node_id) => { |
32a655c1 | 332 | let def_id = scx.tcx().hir.local_def_id(node_id); |
cc61c64b | 333 | let instance = Instance::mono(scx.tcx(), def_id); |
32a655c1 SL |
334 | |
335 | // Sanity check whether this ended up being collected accidentally | |
cc61c64b | 336 | debug_assert!(should_trans_locally(scx.tcx(), &instance)); |
32a655c1 | 337 | |
cc61c64b XL |
338 | let ty = instance_ty(scx, &instance); |
339 | visit_drop_use(scx, ty, true, &mut neighbors); | |
a7813a04 | 340 | |
7453a54e | 341 | recursion_depth_reset = None; |
a7813a04 | 342 | |
cc61c64b | 343 | collect_neighbours(scx, instance, &mut neighbors); |
7453a54e | 344 | } |
54a0048b | 345 | TransItem::Fn(instance) => { |
32a655c1 | 346 | // Sanity check whether this ended up being collected accidentally |
cc61c64b | 347 | debug_assert!(should_trans_locally(scx.tcx(), &instance)); |
32a655c1 | 348 | |
7453a54e | 349 | // Keep track of the monomorphization recursion depth |
a7813a04 | 350 | recursion_depth_reset = Some(check_recursion_limit(scx.tcx(), |
54a0048b | 351 | instance, |
7453a54e | 352 | recursion_depths)); |
476ff2be | 353 | check_type_length_limit(scx.tcx(), instance); |
7453a54e | 354 | |
32a655c1 | 355 | collect_neighbours(scx, instance, &mut neighbors); |
7453a54e | 356 | } |
cc61c64b XL |
357 | TransItem::GlobalAsm(..) => { |
358 | recursion_depth_reset = None; | |
359 | } | |
7453a54e SL |
360 | } |
361 | ||
a7813a04 XL |
362 | record_inlining_canditates(scx.tcx(), starting_point, &neighbors[..], inlining_map); |
363 | ||
7453a54e | 364 | for neighbour in neighbors { |
a7813a04 | 365 | collect_items_rec(scx, neighbour, visited, recursion_depths, inlining_map); |
7453a54e SL |
366 | } |
367 | ||
368 | if let Some((def_id, depth)) = recursion_depth_reset { | |
369 | recursion_depths.insert(def_id, depth); | |
370 | } | |
371 | ||
a7813a04 | 372 | debug!("END collect_items_rec({})", starting_point.to_string(scx.tcx())); |
7453a54e SL |
373 | } |
374 | ||
a7813a04 XL |
375 | fn record_inlining_canditates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
376 | caller: TransItem<'tcx>, | |
377 | callees: &[TransItem<'tcx>], | |
378 | inlining_map: &mut InliningMap<'tcx>) { | |
379 | let is_inlining_candidate = |trans_item: &TransItem<'tcx>| { | |
32a655c1 | 380 | trans_item.instantiation_mode(tcx) == InstantiationMode::LocalCopy |
a7813a04 XL |
381 | }; |
382 | ||
383 | let inlining_candidates = callees.into_iter() | |
384 | .map(|x| *x) | |
385 | .filter(is_inlining_candidate); | |
386 | ||
387 | inlining_map.record_inlining_canditates(caller, inlining_candidates); | |
388 | } | |
389 | ||
390 | fn check_recursion_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
391 | instance: Instance<'tcx>, | |
392 | recursion_depths: &mut DefIdMap<usize>) | |
393 | -> (DefId, usize) { | |
cc61c64b XL |
394 | let def_id = instance.def_id(); |
395 | let recursion_depth = recursion_depths.get(&def_id).cloned().unwrap_or(0); | |
7453a54e SL |
396 | debug!(" => recursion depth={}", recursion_depth); |
397 | ||
cc61c64b XL |
398 | let recursion_depth = if Some(def_id) == tcx.lang_items.drop_in_place_fn() { |
399 | // HACK: drop_in_place creates tight monomorphization loops. Give | |
400 | // it more margin. | |
401 | recursion_depth / 4 | |
402 | } else { | |
403 | recursion_depth | |
404 | }; | |
405 | ||
7453a54e SL |
406 | // Code that needs to instantiate the same function recursively |
407 | // more than the recursion limit is assumed to be causing an | |
408 | // infinite expansion. | |
a7813a04 | 409 | if recursion_depth > tcx.sess.recursion_limit.get() { |
54a0048b SL |
410 | let error = format!("reached the recursion limit while instantiating `{}`", |
411 | instance); | |
cc61c64b | 412 | if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { |
32a655c1 | 413 | tcx.sess.span_fatal(tcx.hir.span(node_id), &error); |
7453a54e | 414 | } else { |
a7813a04 | 415 | tcx.sess.fatal(&error); |
7453a54e SL |
416 | } |
417 | } | |
418 | ||
cc61c64b | 419 | recursion_depths.insert(def_id, recursion_depth + 1); |
7453a54e | 420 | |
cc61c64b | 421 | (def_id, recursion_depth) |
7453a54e SL |
422 | } |
423 | ||
476ff2be SL |
424 | fn check_type_length_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
425 | instance: Instance<'tcx>) | |
426 | { | |
427 | let type_length = instance.substs.types().flat_map(|ty| ty.walk()).count(); | |
428 | debug!(" => type length={}", type_length); | |
429 | ||
430 | // Rust code can easily create exponentially-long types using only a | |
431 | // polynomial recursion depth. Even with the default recursion | |
432 | // depth, you can easily get cases that take >2^60 steps to run, | |
433 | // which means that rustc basically hangs. | |
434 | // | |
435 | // Bail out in these cases to avoid that bad user experience. | |
436 | let type_length_limit = tcx.sess.type_length_limit.get(); | |
437 | if type_length > type_length_limit { | |
438 | // The instance name is already known to be too long for rustc. Use | |
439 | // `{:.64}` to avoid blasting the user's terminal with thousands of | |
440 | // lines of type-name. | |
441 | let instance_name = instance.to_string(); | |
442 | let msg = format!("reached the type-length limit while instantiating `{:.64}...`", | |
443 | instance_name); | |
cc61c64b | 444 | let mut diag = if let Some(node_id) = tcx.hir.as_local_node_id(instance.def_id()) { |
32a655c1 | 445 | tcx.sess.struct_span_fatal(tcx.hir.span(node_id), &msg) |
476ff2be SL |
446 | } else { |
447 | tcx.sess.struct_fatal(&msg) | |
448 | }; | |
449 | ||
450 | diag.note(&format!( | |
451 | "consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate", | |
452 | type_length_limit*2)); | |
453 | diag.emit(); | |
454 | tcx.sess.abort_if_errors(); | |
455 | } | |
456 | } | |
457 | ||
7453a54e | 458 | struct MirNeighborCollector<'a, 'tcx: 'a> { |
a7813a04 | 459 | scx: &'a SharedCrateContext<'a, 'tcx>, |
7453a54e SL |
460 | mir: &'a mir::Mir<'tcx>, |
461 | output: &'a mut Vec<TransItem<'tcx>>, | |
462 | param_substs: &'tcx Substs<'tcx> | |
463 | } | |
464 | ||
465 | impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { | |
466 | ||
9e0c209e | 467 | fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { |
7453a54e SL |
468 | debug!("visiting rvalue {:?}", *rvalue); |
469 | ||
470 | match *rvalue { | |
7453a54e SL |
471 | // When doing an cast from a regular pointer to a fat pointer, we |
472 | // have to instantiate all methods of the trait being cast to, so we | |
473 | // can build the appropriate vtable. | |
474 | mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, target_ty) => { | |
cc61c64b XL |
475 | let target_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, |
476 | &target_ty); | |
5bcae85e | 477 | let source_ty = operand.ty(self.mir, self.scx.tcx()); |
cc61c64b XL |
478 | let source_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, |
479 | &source_ty); | |
a7813a04 | 480 | let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.scx, |
7453a54e SL |
481 | source_ty, |
482 | target_ty); | |
483 | // This could also be a different Unsize instruction, like | |
484 | // from a fixed sized array to a slice. But we are only | |
485 | // interested in things that produce a vtable. | |
486 | if target_ty.is_trait() && !source_ty.is_trait() { | |
a7813a04 | 487 | create_trans_items_for_vtable_methods(self.scx, |
7453a54e SL |
488 | target_ty, |
489 | source_ty, | |
490 | self.output); | |
491 | } | |
492 | } | |
cc61c64b XL |
493 | mir::Rvalue::Cast(mir::CastKind::ReifyFnPointer, ref operand, _) => { |
494 | let fn_ty = operand.ty(self.mir, self.scx.tcx()); | |
495 | let fn_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, | |
496 | &fn_ty); | |
497 | visit_fn_use(self.scx, fn_ty, false, &mut self.output); | |
498 | } | |
8bb4bdeb XL |
499 | mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer, ref operand, _) => { |
500 | let source_ty = operand.ty(self.mir, self.scx.tcx()); | |
7cac9316 XL |
501 | let source_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, |
502 | &source_ty); | |
8bb4bdeb XL |
503 | match source_ty.sty { |
504 | ty::TyClosure(def_id, substs) => { | |
cc61c64b XL |
505 | let instance = monomorphize::resolve_closure( |
506 | self.scx, def_id, substs, ty::ClosureKind::FnOnce); | |
507 | self.output.push(create_fn_trans_item(instance)); | |
8bb4bdeb XL |
508 | } |
509 | _ => bug!(), | |
510 | } | |
511 | } | |
7cac9316 | 512 | mir::Rvalue::NullaryOp(mir::NullOp::Box, _) => { |
cc61c64b XL |
513 | let tcx = self.scx.tcx(); |
514 | let exchange_malloc_fn_def_id = tcx | |
515 | .lang_items | |
516 | .require(ExchangeMallocFnLangItem) | |
517 | .unwrap_or_else(|e| self.scx.sess().fatal(&e)); | |
518 | let instance = Instance::mono(tcx, exchange_malloc_fn_def_id); | |
519 | if should_trans_locally(tcx, &instance) { | |
520 | self.output.push(create_fn_trans_item(instance)); | |
32a655c1 | 521 | } |
7453a54e SL |
522 | } |
523 | _ => { /* not interesting */ } | |
524 | } | |
525 | ||
9e0c209e | 526 | self.super_rvalue(rvalue, location); |
7453a54e SL |
527 | } |
528 | ||
cc61c64b XL |
529 | fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) { |
530 | debug!("visiting constant {:?} @ {:?}", *constant, location); | |
5bcae85e | 531 | |
cc61c64b XL |
532 | if let ty::TyFnDef(..) = constant.ty.sty { |
533 | // function definitions are zero-sized, and only generate | |
534 | // IR when they are called/reified. | |
535 | self.super_constant(constant, location); | |
536 | return | |
7453a54e SL |
537 | } |
538 | ||
cc61c64b XL |
539 | if let mir::Literal::Item { def_id, substs } = constant.literal { |
540 | let substs = self.scx.tcx().trans_apply_param_substs(self.param_substs, | |
541 | &substs); | |
542 | let instance = monomorphize::resolve(self.scx, def_id, substs); | |
543 | collect_neighbours(self.scx, instance, self.output); | |
a7813a04 | 544 | } |
cc61c64b XL |
545 | |
546 | self.super_constant(constant, location); | |
a7813a04 XL |
547 | } |
548 | ||
a7813a04 XL |
549 | fn visit_terminator_kind(&mut self, |
550 | block: mir::BasicBlock, | |
9e0c209e SL |
551 | kind: &mir::TerminatorKind<'tcx>, |
552 | location: Location) { | |
7cac9316 XL |
553 | debug!("visiting terminator {:?} @ {:?}", kind, location); |
554 | ||
a7813a04 XL |
555 | let tcx = self.scx.tcx(); |
556 | match *kind { | |
cc61c64b XL |
557 | mir::TerminatorKind::Call { ref func, .. } => { |
558 | let callee_ty = func.ty(self.mir, tcx); | |
559 | let callee_ty = tcx.trans_apply_param_substs(self.param_substs, &callee_ty); | |
560 | visit_fn_use(self.scx, callee_ty, true, &mut self.output); | |
a7813a04 | 561 | } |
cc61c64b XL |
562 | mir::TerminatorKind::Drop { ref location, .. } | |
563 | mir::TerminatorKind::DropAndReplace { ref location, .. } => { | |
564 | let ty = location.ty(self.mir, self.scx.tcx()) | |
565 | .to_ty(self.scx.tcx()); | |
566 | let ty = tcx.trans_apply_param_substs(self.param_substs, &ty); | |
567 | visit_drop_use(self.scx, ty, true, self.output); | |
568 | } | |
569 | mir::TerminatorKind::Goto { .. } | | |
570 | mir::TerminatorKind::SwitchInt { .. } | | |
571 | mir::TerminatorKind::Resume | | |
572 | mir::TerminatorKind::Return | | |
573 | mir::TerminatorKind::Unreachable | | |
574 | mir::TerminatorKind::Assert { .. } => {} | |
a7813a04 XL |
575 | } |
576 | ||
9e0c209e | 577 | self.super_terminator_kind(block, kind, location); |
7453a54e SL |
578 | } |
579 | } | |
580 | ||
cc61c64b XL |
581 | fn visit_drop_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, |
582 | ty: ty::Ty<'tcx>, | |
583 | is_direct_call: bool, | |
584 | output: &mut Vec<TransItem<'tcx>>) | |
585 | { | |
586 | let instance = monomorphize::resolve_drop_in_place(scx, ty); | |
587 | visit_instance_use(scx, instance, is_direct_call, output); | |
7453a54e SL |
588 | } |
589 | ||
cc61c64b XL |
590 | fn visit_fn_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, |
591 | ty: ty::Ty<'tcx>, | |
592 | is_direct_call: bool, | |
593 | output: &mut Vec<TransItem<'tcx>>) | |
594 | { | |
041b39d2 | 595 | if let ty::TyFnDef(def_id, substs) = ty.sty { |
cc61c64b XL |
596 | let instance = monomorphize::resolve(scx, def_id, substs); |
597 | visit_instance_use(scx, instance, is_direct_call, output); | |
7453a54e | 598 | } |
cc61c64b | 599 | } |
7453a54e | 600 | |
cc61c64b XL |
601 | fn visit_instance_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, |
602 | instance: ty::Instance<'tcx>, | |
603 | is_direct_call: bool, | |
604 | output: &mut Vec<TransItem<'tcx>>) | |
605 | { | |
606 | debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call); | |
607 | if !should_trans_locally(scx.tcx(), &instance) { | |
608 | return | |
7453a54e SL |
609 | } |
610 | ||
cc61c64b XL |
611 | match instance.def { |
612 | ty::InstanceDef::Intrinsic(def_id) => { | |
613 | if !is_direct_call { | |
614 | bug!("intrinsic {:?} being reified", def_id); | |
32a655c1 SL |
615 | } |
616 | } | |
cc61c64b XL |
617 | ty::InstanceDef::Virtual(..) | |
618 | ty::InstanceDef::DropGlue(_, None) => { | |
619 | // don't need to emit shim if we are calling directly. | |
620 | if !is_direct_call { | |
621 | output.push(create_fn_trans_item(instance)); | |
7453a54e SL |
622 | } |
623 | } | |
7cac9316 | 624 | ty::InstanceDef::DropGlue(_, Some(_)) => { |
cc61c64b | 625 | output.push(create_fn_trans_item(instance)); |
7453a54e | 626 | } |
cc61c64b XL |
627 | ty::InstanceDef::ClosureOnceShim { .. } | |
628 | ty::InstanceDef::Item(..) | | |
629 | ty::InstanceDef::FnPtrShim(..) => { | |
630 | output.push(create_fn_trans_item(instance)); | |
32a655c1 | 631 | } |
7453a54e SL |
632 | } |
633 | } | |
634 | ||
cc61c64b XL |
635 | // Returns true if we should translate an instance in the local crate. |
636 | // Returns false if we can just link to the upstream crate and therefore don't | |
637 | // need a translation item. | |
638 | fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instance<'tcx>) | |
639 | -> bool { | |
640 | let def_id = match instance.def { | |
641 | ty::InstanceDef::Item(def_id) => def_id, | |
642 | ty::InstanceDef::ClosureOnceShim { .. } | | |
643 | ty::InstanceDef::Virtual(..) | | |
644 | ty::InstanceDef::FnPtrShim(..) | | |
645 | ty::InstanceDef::DropGlue(..) | | |
646 | ty::InstanceDef::Intrinsic(_) => return true | |
647 | }; | |
648 | match tcx.hir.get_if_local(def_id) { | |
649 | Some(hir_map::NodeForeignItem(..)) => { | |
650 | false // foreign items are linked against, not translated. | |
651 | } | |
652 | Some(_) => true, | |
653 | None => { | |
7cac9316 XL |
654 | if tcx.is_exported_symbol(def_id) || |
655 | tcx.is_foreign_item(def_id) | |
cc61c64b XL |
656 | { |
657 | // We can link to the item in question, no instance needed | |
658 | // in this crate | |
659 | false | |
32a655c1 | 660 | } else { |
7cac9316 | 661 | if !tcx.is_mir_available(def_id) { |
cc61c64b XL |
662 | bug!("Cannot create local trans-item for {:?}", def_id) |
663 | } | |
664 | true | |
32a655c1 SL |
665 | } |
666 | } | |
7453a54e SL |
667 | } |
668 | } | |
669 | ||
670 | /// For given pair of source and target type that occur in an unsizing coercion, | |
671 | /// this function finds the pair of types that determines the vtable linking | |
672 | /// them. | |
673 | /// | |
674 | /// For example, the source type might be `&SomeStruct` and the target type\ | |
675 | /// might be `&SomeTrait` in a cast like: | |
676 | /// | |
677 | /// let src: &SomeStruct = ...; | |
678 | /// let target = src as &SomeTrait; | |
679 | /// | |
680 | /// Then the output of this function would be (SomeStruct, SomeTrait) since for | |
681 | /// constructing the `target` fat-pointer we need the vtable for that pair. | |
682 | /// | |
683 | /// Things can get more complicated though because there's also the case where | |
684 | /// the unsized type occurs as a field: | |
685 | /// | |
686 | /// ```rust | |
687 | /// struct ComplexStruct<T: ?Sized> { | |
688 | /// a: u32, | |
689 | /// b: f64, | |
690 | /// c: T | |
691 | /// } | |
692 | /// ``` | |
693 | /// | |
694 | /// In this case, if `T` is sized, `&ComplexStruct<T>` is a thin pointer. If `T` | |
695 | /// is unsized, `&SomeStruct` is a fat pointer, and the vtable it points to is | |
696 | /// for the pair of `T` (which is a trait) and the concrete type that `T` was | |
697 | /// originally coerced from: | |
698 | /// | |
699 | /// let src: &ComplexStruct<SomeStruct> = ...; | |
700 | /// let target = src as &ComplexStruct<SomeTrait>; | |
701 | /// | |
702 | /// Again, we want this `find_vtable_types_for_unsizing()` to provide the pair | |
703 | /// `(SomeStruct, SomeTrait)`. | |
704 | /// | |
705 | /// Finally, there is also the case of custom unsizing coercions, e.g. for | |
706 | /// smart pointers such as `Rc` and `Arc`. | |
a7813a04 | 707 | fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, |
7453a54e SL |
708 | source_ty: ty::Ty<'tcx>, |
709 | target_ty: ty::Ty<'tcx>) | |
710 | -> (ty::Ty<'tcx>, ty::Ty<'tcx>) { | |
32a655c1 SL |
711 | let ptr_vtable = |inner_source: ty::Ty<'tcx>, inner_target: ty::Ty<'tcx>| { |
712 | if !scx.type_is_sized(inner_source) { | |
713 | (inner_source, inner_target) | |
714 | } else { | |
715 | scx.tcx().struct_lockstep_tails(inner_source, inner_target) | |
716 | } | |
717 | }; | |
7453a54e | 718 | match (&source_ty.sty, &target_ty.sty) { |
7453a54e SL |
719 | (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }), |
720 | &ty::TyRef(_, ty::TypeAndMut { ty: b, .. })) | | |
721 | (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }), | |
722 | &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) | | |
723 | (&ty::TyRawPtr(ty::TypeAndMut { ty: a, .. }), | |
724 | &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) => { | |
32a655c1 SL |
725 | ptr_vtable(a, b) |
726 | } | |
727 | (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) if def_a.is_box() && def_b.is_box() => { | |
728 | ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty()) | |
7453a54e SL |
729 | } |
730 | ||
9e0c209e SL |
731 | (&ty::TyAdt(source_adt_def, source_substs), |
732 | &ty::TyAdt(target_adt_def, target_substs)) => { | |
7453a54e SL |
733 | assert_eq!(source_adt_def, target_adt_def); |
734 | ||
cc61c64b XL |
735 | let kind = |
736 | monomorphize::custom_coerce_unsize_info(scx, source_ty, target_ty); | |
7453a54e SL |
737 | |
738 | let coerce_index = match kind { | |
739 | CustomCoerceUnsized::Struct(i) => i | |
740 | }; | |
741 | ||
742 | let source_fields = &source_adt_def.struct_variant().fields; | |
743 | let target_fields = &target_adt_def.struct_variant().fields; | |
744 | ||
745 | assert!(coerce_index < source_fields.len() && | |
746 | source_fields.len() == target_fields.len()); | |
747 | ||
a7813a04 XL |
748 | find_vtable_types_for_unsizing(scx, |
749 | source_fields[coerce_index].ty(scx.tcx(), | |
7453a54e | 750 | source_substs), |
a7813a04 | 751 | target_fields[coerce_index].ty(scx.tcx(), |
7453a54e SL |
752 | target_substs)) |
753 | } | |
54a0048b SL |
754 | _ => bug!("find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}", |
755 | source_ty, | |
756 | target_ty) | |
7453a54e SL |
757 | } |
758 | } | |
759 | ||
cc61c64b XL |
760 | fn create_fn_trans_item<'a, 'tcx>(instance: Instance<'tcx>) -> TransItem<'tcx> { |
761 | debug!("create_fn_trans_item(instance={})", instance); | |
762 | TransItem::Fn(instance) | |
7453a54e SL |
763 | } |
764 | ||
765 | /// Creates a `TransItem` for each method that is referenced by the vtable for | |
766 | /// the given trait/impl pair. | |
a7813a04 | 767 | fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, |
7453a54e SL |
768 | trait_ty: ty::Ty<'tcx>, |
769 | impl_ty: ty::Ty<'tcx>, | |
770 | output: &mut Vec<TransItem<'tcx>>) { | |
8bb4bdeb XL |
771 | assert!(!trait_ty.needs_subst() && !trait_ty.has_escaping_regions() && |
772 | !impl_ty.needs_subst() && !impl_ty.has_escaping_regions()); | |
7453a54e | 773 | |
476ff2be SL |
774 | if let ty::TyDynamic(ref trait_ty, ..) = trait_ty.sty { |
775 | if let Some(principal) = trait_ty.principal() { | |
776 | let poly_trait_ref = principal.with_self_ty(scx.tcx(), impl_ty); | |
8bb4bdeb XL |
777 | assert!(!poly_trait_ref.has_escaping_regions()); |
778 | ||
476ff2be SL |
779 | // Walk all methods of the trait, including those of its supertraits |
780 | let methods = traits::get_vtable_methods(scx.tcx(), poly_trait_ref); | |
781 | let methods = methods.filter_map(|method| method) | |
cc61c64b XL |
782 | .map(|(def_id, substs)| monomorphize::resolve(scx, def_id, substs)) |
783 | .filter(|&instance| should_trans_locally(scx.tcx(), &instance)) | |
784 | .map(|instance| create_fn_trans_item(instance)); | |
476ff2be SL |
785 | output.extend(methods); |
786 | } | |
9e0c209e | 787 | // Also add the destructor |
cc61c64b | 788 | visit_drop_use(scx, impl_ty, false, output); |
7453a54e SL |
789 | } |
790 | } | |
791 | ||
792 | //=----------------------------------------------------------------------------- | |
793 | // Root Collection | |
794 | //=----------------------------------------------------------------------------- | |
795 | ||
796 | struct RootCollector<'b, 'a: 'b, 'tcx: 'a + 'b> { | |
a7813a04 | 797 | scx: &'b SharedCrateContext<'a, 'tcx>, |
7453a54e SL |
798 | mode: TransItemCollectionMode, |
799 | output: &'b mut Vec<TransItem<'tcx>>, | |
7453a54e SL |
800 | } |
801 | ||
476ff2be | 802 | impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { |
7453a54e | 803 | fn visit_item(&mut self, item: &'v hir::Item) { |
7453a54e SL |
804 | match item.node { |
805 | hir::ItemExternCrate(..) | | |
806 | hir::ItemUse(..) | | |
807 | hir::ItemForeignMod(..) | | |
808 | hir::ItemTy(..) | | |
809 | hir::ItemDefaultImpl(..) | | |
810 | hir::ItemTrait(..) | | |
7453a54e SL |
811 | hir::ItemMod(..) => { |
812 | // Nothing to do, just keep recursing... | |
813 | } | |
814 | ||
815 | hir::ItemImpl(..) => { | |
816 | if self.mode == TransItemCollectionMode::Eager { | |
9e0c209e | 817 | create_trans_items_for_default_impls(self.scx, |
7453a54e | 818 | item, |
7453a54e SL |
819 | self.output); |
820 | } | |
821 | } | |
822 | ||
9e0c209e SL |
823 | hir::ItemEnum(_, ref generics) | |
824 | hir::ItemStruct(_, ref generics) | | |
825 | hir::ItemUnion(_, ref generics) => { | |
7453a54e | 826 | if !generics.is_parameterized() { |
7453a54e | 827 | if self.mode == TransItemCollectionMode::Eager { |
32a655c1 | 828 | let def_id = self.scx.tcx().hir.local_def_id(item.id); |
7453a54e | 829 | debug!("RootCollector: ADT drop-glue for {}", |
476ff2be | 830 | def_id_to_string(self.scx.tcx(), def_id)); |
7453a54e | 831 | |
8bb4bdeb | 832 | let ty = def_ty(self.scx, def_id, Substs::empty()); |
cc61c64b | 833 | visit_drop_use(self.scx, ty, true, self.output); |
7453a54e SL |
834 | } |
835 | } | |
836 | } | |
cc61c64b XL |
837 | hir::ItemGlobalAsm(..) => { |
838 | debug!("RootCollector: ItemGlobalAsm({})", | |
839 | def_id_to_string(self.scx.tcx(), | |
840 | self.scx.tcx().hir.local_def_id(item.id))); | |
841 | self.output.push(TransItem::GlobalAsm(item.id)); | |
842 | } | |
7453a54e SL |
843 | hir::ItemStatic(..) => { |
844 | debug!("RootCollector: ItemStatic({})", | |
a7813a04 | 845 | def_id_to_string(self.scx.tcx(), |
32a655c1 | 846 | self.scx.tcx().hir.local_def_id(item.id))); |
7453a54e SL |
847 | self.output.push(TransItem::Static(item.id)); |
848 | } | |
5bcae85e SL |
849 | hir::ItemConst(..) => { |
850 | // const items only generate translation items if they are | |
851 | // actually used somewhere. Just declaring them is insufficient. | |
852 | } | |
9e0c209e | 853 | hir::ItemFn(.., ref generics, _) => { |
5bcae85e | 854 | if !generics.is_type_parameterized() { |
32a655c1 | 855 | let def_id = self.scx.tcx().hir.local_def_id(item.id); |
7453a54e SL |
856 | |
857 | debug!("RootCollector: ItemFn({})", | |
a7813a04 | 858 | def_id_to_string(self.scx.tcx(), def_id)); |
7453a54e | 859 | |
cc61c64b | 860 | let instance = Instance::mono(self.scx.tcx(), def_id); |
54a0048b | 861 | self.output.push(TransItem::Fn(instance)); |
7453a54e SL |
862 | } |
863 | } | |
864 | } | |
7453a54e SL |
865 | } |
866 | ||
32a655c1 SL |
867 | fn visit_trait_item(&mut self, _: &'v hir::TraitItem) { |
868 | // Even if there's a default body with no explicit generics, | |
869 | // it's still generic over some `Self: Trait`, so not a root. | |
870 | } | |
871 | ||
7453a54e SL |
872 | fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) { |
873 | match ii.node { | |
874 | hir::ImplItemKind::Method(hir::MethodSig { | |
875 | ref generics, | |
7453a54e | 876 | .. |
5bcae85e | 877 | }, _) => { |
32a655c1 | 878 | let hir_map = &self.scx.tcx().hir; |
7453a54e SL |
879 | let parent_node_id = hir_map.get_parent_node(ii.id); |
880 | let is_impl_generic = match hir_map.expect_item(parent_node_id) { | |
881 | &hir::Item { | |
7cac9316 | 882 | node: hir::ItemImpl(_, _, _, ref generics, ..), |
7453a54e SL |
883 | .. |
884 | } => { | |
885 | generics.is_type_parameterized() | |
886 | } | |
887 | _ => { | |
54a0048b | 888 | bug!() |
7453a54e SL |
889 | } |
890 | }; | |
891 | ||
892 | if !generics.is_type_parameterized() && !is_impl_generic { | |
32a655c1 | 893 | let def_id = self.scx.tcx().hir.local_def_id(ii.id); |
7453a54e SL |
894 | |
895 | debug!("RootCollector: MethodImplItem({})", | |
a7813a04 | 896 | def_id_to_string(self.scx.tcx(), def_id)); |
7453a54e | 897 | |
cc61c64b | 898 | let instance = Instance::mono(self.scx.tcx(), def_id); |
54a0048b | 899 | self.output.push(TransItem::Fn(instance)); |
7453a54e SL |
900 | } |
901 | } | |
902 | _ => { /* Nothing to do here */ } | |
903 | } | |
7453a54e SL |
904 | } |
905 | } | |
906 | ||
9e0c209e | 907 | fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, |
7453a54e | 908 | item: &'tcx hir::Item, |
7453a54e | 909 | output: &mut Vec<TransItem<'tcx>>) { |
9e0c209e | 910 | let tcx = scx.tcx(); |
7453a54e SL |
911 | match item.node { |
912 | hir::ItemImpl(_, | |
7cac9316 | 913 | _, |
7453a54e SL |
914 | _, |
915 | ref generics, | |
9e0c209e | 916 | .., |
476ff2be | 917 | ref impl_item_refs) => { |
7453a54e SL |
918 | if generics.is_type_parameterized() { |
919 | return | |
920 | } | |
921 | ||
32a655c1 | 922 | let impl_def_id = tcx.hir.local_def_id(item.id); |
7453a54e SL |
923 | |
924 | debug!("create_trans_items_for_default_impls(item={})", | |
a7813a04 | 925 | def_id_to_string(tcx, impl_def_id)); |
7453a54e SL |
926 | |
927 | if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) { | |
a7813a04 | 928 | let callee_substs = tcx.erase_regions(&trait_ref.substs); |
476ff2be SL |
929 | let overridden_methods: FxHashSet<_> = |
930 | impl_item_refs.iter() | |
931 | .map(|iiref| iiref.name) | |
932 | .collect(); | |
9e0c209e SL |
933 | for method in tcx.provided_trait_methods(trait_ref.def_id) { |
934 | if overridden_methods.contains(&method.name) { | |
7453a54e SL |
935 | continue; |
936 | } | |
937 | ||
7cac9316 | 938 | if !tcx.generics_of(method.def_id).types.is_empty() { |
7453a54e SL |
939 | continue; |
940 | } | |
941 | ||
cc61c64b XL |
942 | let instance = |
943 | monomorphize::resolve(scx, method.def_id, callee_substs); | |
944 | ||
041b39d2 XL |
945 | let trans_item = create_fn_trans_item(instance); |
946 | if trans_item.is_instantiable(tcx) && should_trans_locally(tcx, &instance) { | |
947 | output.push(trans_item); | |
7453a54e SL |
948 | } |
949 | } | |
950 | } | |
951 | } | |
952 | _ => { | |
54a0048b | 953 | bug!() |
7453a54e SL |
954 | } |
955 | } | |
956 | } | |
957 | ||
32a655c1 SL |
958 | /// Scan the MIR in order to find function calls, closures, and drop-glue |
959 | fn collect_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, | |
960 | instance: Instance<'tcx>, | |
961 | output: &mut Vec<TransItem<'tcx>>) | |
5bcae85e | 962 | { |
cc61c64b | 963 | let mir = scx.tcx().instance_mir(instance.def); |
5bcae85e | 964 | |
32a655c1 | 965 | let mut visitor = MirNeighborCollector { |
5bcae85e SL |
966 | scx: scx, |
967 | mir: &mir, | |
968 | output: output, | |
32a655c1 | 969 | param_substs: instance.substs |
5bcae85e | 970 | }; |
7453a54e | 971 | |
5bcae85e SL |
972 | visitor.visit_mir(&mir); |
973 | for promoted in &mir.promoted { | |
32a655c1 | 974 | visitor.mir = promoted; |
5bcae85e | 975 | visitor.visit_mir(promoted); |
7453a54e SL |
976 | } |
977 | } | |
476ff2be SL |
978 | |
979 | fn def_id_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
980 | def_id: DefId) | |
981 | -> String { | |
982 | let mut output = String::new(); | |
983 | let printer = DefPathBasedNames::new(tcx, false, false); | |
984 | printer.push_def_path(def_id, &mut output); | |
985 | output | |
986 | } |