]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans_item.rs
Auto merge of #35166 - nikomatsakis:incr-comp-ice-34991-2, r=mw
[rust.git] / src / librustc_trans / trans_item.rs
1 // Copyright 2016 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 //! Walks the crate looking for items/impl-items/trait-items that have
12 //! either a `rustc_symbol_name` or `rustc_item_path` attribute and
13 //! generates an error giving, respectively, the symbol name or
14 //! item-path. This is used for unit testing the code that generates
15 //! paths etc in all kinds of annoying scenarios.
16
17 use attributes;
18 use base;
19 use consts;
20 use context::{CrateContext, SharedCrateContext};
21 use declare;
22 use glue::DropGlueKind;
23 use llvm;
24 use monomorphize::{self, Instance};
25 use inline;
26 use rustc::dep_graph::DepNode;
27 use rustc::hir;
28 use rustc::hir::map as hir_map;
29 use rustc::hir::def_id::DefId;
30 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
31 use rustc::ty::subst;
32 use rustc_const_eval::fatal_const_eval_err;
33 use std::hash::{Hash, Hasher};
34 use syntax::ast::{self, NodeId};
35 use syntax::{attr,errors};
36 use type_of;
37 use glue;
38 use abi::{Abi, FnType};
39 use back::symbol_names;
40
41 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
42 pub enum TransItem<'tcx> {
43     DropGlue(DropGlueKind<'tcx>),
44     Fn(Instance<'tcx>),
45     Static(NodeId)
46 }
47
48 impl<'tcx> Hash for TransItem<'tcx> {
49     fn hash<H: Hasher>(&self, s: &mut H) {
50         match *self {
51             TransItem::DropGlue(t) => {
52                 0u8.hash(s);
53                 t.hash(s);
54             },
55             TransItem::Fn(instance) => {
56                 1u8.hash(s);
57                 instance.def.hash(s);
58                 (instance.substs as *const _ as usize).hash(s);
59             }
60             TransItem::Static(node_id) => {
61                 2u8.hash(s);
62                 node_id.hash(s);
63             }
64         };
65     }
66 }
67
68 impl<'a, 'tcx> TransItem<'tcx> {
69
70     pub fn define(&self, ccx: &CrateContext<'a, 'tcx>) {
71         debug!("BEGIN IMPLEMENTING '{} ({})' in cgu {}",
72                   self.to_string(ccx.tcx()),
73                   self.to_raw_string(),
74                   ccx.codegen_unit().name());
75
76         // (*) This code executes in the context of a dep-node for the
77         // entire CGU. In some cases, we introduce dep-nodes for
78         // particular items that we are translating (these nodes will
79         // have read edges coming into the CGU node). These smaller
80         // nodes are not needed for correctness -- we always
81         // invalidate an entire CGU at a time -- but they enable
82         // finer-grained testing, since you can write tests that check
83         // that the incoming edges to a particular fn are from a
84         // particular set.
85
86         match *self {
87             TransItem::Static(node_id) => {
88                 let def_id = ccx.tcx().map.local_def_id(node_id);
89                 let _task = ccx.tcx().dep_graph.in_task(DepNode::TransCrateItem(def_id)); // (*)
90                 let item = ccx.tcx().map.expect_item(node_id);
91                 if let hir::ItemStatic(_, m, ref expr) = item.node {
92                     match consts::trans_static(&ccx, m, expr, item.id, &item.attrs) {
93                         Ok(_) => { /* Cool, everything's alright. */ },
94                         Err(err) => {
95                             // FIXME: shouldn't this be a `span_err`?
96                             fatal_const_eval_err(
97                                 ccx.tcx(), &err, expr.span, "static");
98                         }
99                     };
100                 } else {
101                     span_bug!(item.span, "Mismatch between hir::Item type and TransItem type")
102                 }
103             }
104             TransItem::Fn(instance) => {
105                 let _task = ccx.tcx().dep_graph.in_task(
106                     DepNode::TransCrateItem(instance.def)); // (*)
107
108                 base::trans_instance(&ccx, instance);
109             }
110             TransItem::DropGlue(dg) => {
111                 glue::implement_drop_glue(&ccx, dg);
112             }
113         }
114
115         debug!("END IMPLEMENTING '{} ({})' in cgu {}",
116                self.to_string(ccx.tcx()),
117                self.to_raw_string(),
118                ccx.codegen_unit().name());
119     }
120
121     pub fn predefine(&self,
122                      ccx: &CrateContext<'a, 'tcx>,
123                      linkage: llvm::Linkage) {
124         debug!("BEGIN PREDEFINING '{} ({})' in cgu {}",
125                self.to_string(ccx.tcx()),
126                self.to_raw_string(),
127                ccx.codegen_unit().name());
128
129         let symbol_name = ccx.symbol_map()
130                              .get_or_compute(ccx.shared(), *self);
131
132         debug!("symbol {}", &symbol_name);
133
134         match *self {
135             TransItem::Static(node_id) => {
136                 TransItem::predefine_static(ccx, node_id, linkage, &symbol_name);
137             }
138             TransItem::Fn(instance) => {
139                 TransItem::predefine_fn(ccx, instance, linkage, &symbol_name);
140             }
141             TransItem::DropGlue(dg) => {
142                 TransItem::predefine_drop_glue(ccx, dg, linkage, &symbol_name);
143             }
144         }
145
146         debug!("END PREDEFINING '{} ({})' in cgu {}",
147                self.to_string(ccx.tcx()),
148                self.to_raw_string(),
149                ccx.codegen_unit().name());
150     }
151
152     fn predefine_static(ccx: &CrateContext<'a, 'tcx>,
153                         node_id: ast::NodeId,
154                         linkage: llvm::Linkage,
155                         symbol_name: &str) {
156         let def_id = ccx.tcx().map.local_def_id(node_id);
157         let ty = ccx.tcx().lookup_item_type(def_id).ty;
158         let llty = type_of::type_of(ccx, ty);
159
160         match ccx.tcx().map.get(node_id) {
161             hir::map::NodeItem(&hir::Item {
162                 span, node: hir::ItemStatic(..), ..
163             }) => {
164                 let g = declare::define_global(ccx, symbol_name, llty).unwrap_or_else(|| {
165                     ccx.sess().span_fatal(span,
166                         &format!("symbol `{}` is already defined", symbol_name))
167                 });
168
169                 unsafe { llvm::LLVMSetLinkage(g, linkage) };
170             }
171
172             item => bug!("predefine_static: expected static, found {:?}", item)
173         }
174     }
175
176     fn predefine_fn(ccx: &CrateContext<'a, 'tcx>,
177                     instance: Instance<'tcx>,
178                     linkage: llvm::Linkage,
179                     symbol_name: &str) {
180         assert!(!instance.substs.types.needs_infer() &&
181                 !instance.substs.types.has_param_types());
182
183         let instance = inline::maybe_inline_instance(ccx, instance);
184
185         let item_ty = ccx.tcx().lookup_item_type(instance.def).ty;
186         let item_ty = ccx.tcx().erase_regions(&item_ty);
187         let mono_ty = monomorphize::apply_param_substs(ccx.tcx(), instance.substs, &item_ty);
188
189         let fn_node_id = ccx.tcx().map.as_local_node_id(instance.def).unwrap();
190         let map_node = errors::expect(
191             ccx.sess().diagnostic(),
192             ccx.tcx().map.find(fn_node_id),
193             || {
194                 format!("while instantiating `{}`, couldn't find it in \
195                      the item map (may have attempted to monomorphize \
196                      an item defined in a different crate?)",
197                     instance)
198             });
199
200         match map_node {
201             hir_map::NodeItem(&hir::Item {
202                 ref attrs, node: hir::ItemFn(..), ..
203             }) |
204             hir_map::NodeTraitItem(&hir::TraitItem {
205                 ref attrs, node: hir::MethodTraitItem(..), ..
206             }) |
207             hir_map::NodeImplItem(&hir::ImplItem {
208                 ref attrs, node: hir::ImplItemKind::Method(..), ..
209             }) => {
210                 let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty);
211                 unsafe { llvm::LLVMSetLinkage(lldecl, linkage) };
212                 base::set_link_section(ccx, lldecl, attrs);
213                 if linkage == llvm::LinkOnceODRLinkage ||
214                    linkage == llvm::WeakODRLinkage {
215                     llvm::SetUniqueComdat(ccx.llmod(), lldecl);
216                 }
217
218                 attributes::from_fn_attrs(ccx, attrs, lldecl);
219                 ccx.instances().borrow_mut().insert(instance, lldecl);
220             }
221             _ => bug!("Invalid item for TransItem::Fn: `{:?}`", map_node)
222         };
223
224     }
225
226     fn predefine_drop_glue(ccx: &CrateContext<'a, 'tcx>,
227                            dg: glue::DropGlueKind<'tcx>,
228                            linkage: llvm::Linkage,
229                            symbol_name: &str) {
230         let tcx = ccx.tcx();
231         assert_eq!(dg.ty(), glue::get_drop_glue_type(tcx, dg.ty()));
232         let t = dg.ty();
233
234         let sig = ty::FnSig {
235             inputs: vec![tcx.mk_mut_ptr(tcx.types.i8)],
236             output: ty::FnOutput::FnConverging(tcx.mk_nil()),
237             variadic: false,
238         };
239
240         // Create a FnType for fn(*mut i8) and substitute the real type in
241         // later - that prevents FnType from splitting fat pointers up.
242         let mut fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);
243         fn_ty.args[0].original_ty = type_of::type_of(ccx, t).ptr_to();
244         let llfnty = fn_ty.llvm_type(ccx);
245
246         assert!(declare::get_defined_value(ccx, symbol_name).is_none());
247         let llfn = declare::declare_cfn(ccx, symbol_name, llfnty);
248         unsafe { llvm::LLVMSetLinkage(llfn, linkage) };
249         if linkage == llvm::LinkOnceODRLinkage ||
250            linkage == llvm::WeakODRLinkage {
251             llvm::SetUniqueComdat(ccx.llmod(), llfn);
252         }
253         attributes::set_frame_pointer_elimination(ccx, llfn);
254         ccx.drop_glues().borrow_mut().insert(dg, (llfn, fn_ty));
255     }
256
257     pub fn compute_symbol_name(&self,
258                                scx: &SharedCrateContext<'a, 'tcx>) -> String {
259         match *self {
260             TransItem::Fn(instance) => instance.symbol_name(scx),
261             TransItem::Static(node_id) => {
262                 let def_id = scx.tcx().map.local_def_id(node_id);
263                 Instance::mono(scx, def_id).symbol_name(scx)
264             }
265             TransItem::DropGlue(dg) => {
266                 let prefix = match dg {
267                     DropGlueKind::Ty(_) => "drop",
268                     DropGlueKind::TyContents(_) => "drop_contents",
269                 };
270                 symbol_names::exported_name_from_type_and_prefix(scx, dg.ty(), prefix)
271             }
272         }
273     }
274
275     pub fn requests_inline(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
276         match *self {
277             TransItem::Fn(ref instance) => {
278                 !instance.substs.types.is_empty() || {
279                     let attributes = tcx.get_attrs(instance.def);
280                     attr::requests_inline(&attributes[..])
281                 }
282             }
283             TransItem::DropGlue(..) => true,
284             TransItem::Static(..)   => false,
285         }
286     }
287
288     pub fn is_from_extern_crate(&self) -> bool {
289         match *self {
290             TransItem::Fn(ref instance) => !instance.def.is_local(),
291             TransItem::DropGlue(..) |
292             TransItem::Static(..)   => false,
293         }
294     }
295
296     pub fn is_instantiated_only_on_demand(&self) -> bool {
297         match *self {
298             TransItem::Fn(ref instance) => !instance.def.is_local() ||
299                                            !instance.substs.types.is_empty(),
300             TransItem::DropGlue(..) => true,
301             TransItem::Static(..)   => false,
302         }
303     }
304
305     pub fn is_generic_fn(&self) -> bool {
306         match *self {
307             TransItem::Fn(ref instance) => !instance.substs.types.is_empty(),
308             TransItem::DropGlue(..) |
309             TransItem::Static(..)   => false,
310         }
311     }
312
313     pub fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<llvm::Linkage> {
314         let def_id = match *self {
315             TransItem::Fn(ref instance) => instance.def,
316             TransItem::Static(node_id) => tcx.map.local_def_id(node_id),
317             TransItem::DropGlue(..) => return None,
318         };
319
320         let attributes = tcx.get_attrs(def_id);
321         if let Some(name) = attr::first_attr_value_str_by_name(&attributes, "linkage") {
322             if let Some(linkage) = base::llvm_linkage_by_name(&name) {
323                 Some(linkage)
324             } else {
325                 let span = tcx.map.span_if_local(def_id);
326                 if let Some(span) = span {
327                     tcx.sess.span_fatal(span, "invalid linkage specified")
328                 } else {
329                     tcx.sess.fatal(&format!("invalid linkage specified: {}", name))
330                 }
331             }
332         } else {
333             None
334         }
335     }
336
337     pub fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
338         let hir_map = &tcx.map;
339
340         return match *self {
341             TransItem::DropGlue(dg) => {
342                 let mut s = String::with_capacity(32);
343                 match dg {
344                     DropGlueKind::Ty(_) => s.push_str("drop-glue "),
345                     DropGlueKind::TyContents(_) => s.push_str("drop-glue-contents "),
346                 };
347                 push_unique_type_name(tcx, dg.ty(), &mut s);
348                 s
349             }
350             TransItem::Fn(instance) => {
351                 to_string_internal(tcx, "fn ", instance)
352             },
353             TransItem::Static(node_id) => {
354                 let def_id = hir_map.local_def_id(node_id);
355                 let instance = Instance::new(def_id,
356                                              tcx.mk_substs(subst::Substs::empty()));
357                 to_string_internal(tcx, "static ", instance)
358             },
359         };
360
361         fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
362                                         prefix: &str,
363                                         instance: Instance<'tcx>)
364                                         -> String {
365             let mut result = String::with_capacity(32);
366             result.push_str(prefix);
367             push_instance_as_string(tcx, instance, &mut result);
368             result
369         }
370     }
371
372     pub fn to_raw_string(&self) -> String {
373         match *self {
374             TransItem::DropGlue(dg) => {
375                 let prefix = match dg {
376                     DropGlueKind::Ty(_) => "Ty",
377                     DropGlueKind::TyContents(_) => "TyContents",
378                 };
379                 format!("DropGlue({}: {})", prefix, dg.ty() as *const _ as usize)
380             }
381             TransItem::Fn(instance) => {
382                 format!("Fn({:?}, {})",
383                          instance.def,
384                          instance.substs as *const _ as usize)
385             }
386             TransItem::Static(id) => {
387                 format!("Static({:?})", id)
388             }
389         }
390     }
391 }
392
393
394 //=-----------------------------------------------------------------------------
395 // TransItem String Keys
396 //=-----------------------------------------------------------------------------
397
398 // The code below allows for producing a unique string key for a trans item.
399 // These keys are used by the handwritten auto-tests, so they need to be
400 // predictable and human-readable.
401 //
402 // Note: A lot of this could looks very similar to what's already in the
403 //       ppaux module. It would be good to refactor things so we only have one
404 //       parameterizable implementation for printing types.
405
406 /// Same as `unique_type_name()` but with the result pushed onto the given
407 /// `output` parameter.
408 pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
409                                        t: ty::Ty<'tcx>,
410                                        output: &mut String) {
411     match t.sty {
412         ty::TyBool              => output.push_str("bool"),
413         ty::TyChar              => output.push_str("char"),
414         ty::TyStr               => output.push_str("str"),
415         ty::TyInt(ast::IntTy::Is)    => output.push_str("isize"),
416         ty::TyInt(ast::IntTy::I8)    => output.push_str("i8"),
417         ty::TyInt(ast::IntTy::I16)   => output.push_str("i16"),
418         ty::TyInt(ast::IntTy::I32)   => output.push_str("i32"),
419         ty::TyInt(ast::IntTy::I64)   => output.push_str("i64"),
420         ty::TyUint(ast::UintTy::Us)   => output.push_str("usize"),
421         ty::TyUint(ast::UintTy::U8)   => output.push_str("u8"),
422         ty::TyUint(ast::UintTy::U16)  => output.push_str("u16"),
423         ty::TyUint(ast::UintTy::U32)  => output.push_str("u32"),
424         ty::TyUint(ast::UintTy::U64)  => output.push_str("u64"),
425         ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"),
426         ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"),
427         ty::TyStruct(adt_def, substs) |
428         ty::TyEnum(adt_def, substs) => {
429             push_item_name(tcx, adt_def.did, output);
430             push_type_params(tcx, &substs.types, &[], output);
431         },
432         ty::TyTuple(component_types) => {
433             output.push('(');
434             for &component_type in component_types {
435                 push_unique_type_name(tcx, component_type, output);
436                 output.push_str(", ");
437             }
438             if !component_types.is_empty() {
439                 output.pop();
440                 output.pop();
441             }
442             output.push(')');
443         },
444         ty::TyBox(inner_type) => {
445             output.push_str("Box<");
446             push_unique_type_name(tcx, inner_type, output);
447             output.push('>');
448         },
449         ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => {
450             output.push('*');
451             match mutbl {
452                 hir::MutImmutable => output.push_str("const "),
453                 hir::MutMutable => output.push_str("mut "),
454             }
455
456             push_unique_type_name(tcx, inner_type, output);
457         },
458         ty::TyRef(_, ty::TypeAndMut { ty: inner_type, mutbl }) => {
459             output.push('&');
460             if mutbl == hir::MutMutable {
461                 output.push_str("mut ");
462             }
463
464             push_unique_type_name(tcx, inner_type, output);
465         },
466         ty::TyArray(inner_type, len) => {
467             output.push('[');
468             push_unique_type_name(tcx, inner_type, output);
469             output.push_str(&format!("; {}", len));
470             output.push(']');
471         },
472         ty::TySlice(inner_type) => {
473             output.push('[');
474             push_unique_type_name(tcx, inner_type, output);
475             output.push(']');
476         },
477         ty::TyTrait(ref trait_data) => {
478             push_item_name(tcx, trait_data.principal.skip_binder().def_id, output);
479             push_type_params(tcx,
480                              &trait_data.principal.skip_binder().substs.types,
481                              &trait_data.bounds.projection_bounds,
482                              output);
483         },
484         ty::TyFnDef(_, _, &ty::BareFnTy{ unsafety, abi, ref sig } ) |
485         ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {
486             if unsafety == hir::Unsafety::Unsafe {
487                 output.push_str("unsafe ");
488             }
489
490             if abi != ::abi::Abi::Rust {
491                 output.push_str("extern \"");
492                 output.push_str(abi.name());
493                 output.push_str("\" ");
494             }
495
496             output.push_str("fn(");
497
498             let sig = tcx.erase_late_bound_regions(sig);
499             if !sig.inputs.is_empty() {
500                 for &parameter_type in &sig.inputs {
501                     push_unique_type_name(tcx, parameter_type, output);
502                     output.push_str(", ");
503                 }
504                 output.pop();
505                 output.pop();
506             }
507
508             if sig.variadic {
509                 if !sig.inputs.is_empty() {
510                     output.push_str(", ...");
511                 } else {
512                     output.push_str("...");
513                 }
514             }
515
516             output.push(')');
517
518             match sig.output {
519                 ty::FnConverging(result_type) if result_type.is_nil() => {}
520                 ty::FnConverging(result_type) => {
521                     output.push_str(" -> ");
522                     push_unique_type_name(tcx, result_type, output);
523                 }
524                 ty::FnDiverging => {
525                     output.push_str(" -> !");
526                 }
527             }
528         },
529         ty::TyClosure(def_id, ref closure_substs) => {
530             push_item_name(tcx, def_id, output);
531             output.push_str("{");
532             output.push_str(&format!("{}:{}", def_id.krate, def_id.index.as_usize()));
533             output.push_str("}");
534             push_type_params(tcx, &closure_substs.func_substs.types, &[], output);
535         }
536         ty::TyError |
537         ty::TyInfer(_) |
538         ty::TyProjection(..) |
539         ty::TyParam(_) => {
540             bug!("debuginfo: Trying to create type name for \
541                   unexpected type: {:?}", t);
542         }
543     }
544 }
545
546 fn push_item_name(tcx: TyCtxt,
547                   def_id: DefId,
548                   output: &mut String) {
549     let def_path = tcx.def_path(def_id);
550
551     // some_crate::
552     output.push_str(&tcx.crate_name(def_path.krate));
553     output.push_str("::");
554
555     // foo::bar::ItemName::
556     for part in tcx.def_path(def_id).data {
557         output.push_str(&format!("{}[{}]::",
558                         part.data.as_interned_str(),
559                         part.disambiguator));
560     }
561
562     // remove final "::"
563     output.pop();
564     output.pop();
565 }
566
567 fn push_type_params<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
568                               types: &'tcx subst::VecPerParamSpace<Ty<'tcx>>,
569                               projections: &[ty::PolyProjectionPredicate<'tcx>],
570                               output: &mut String) {
571     if types.is_empty() && projections.is_empty() {
572         return;
573     }
574
575     output.push('<');
576
577     for &type_parameter in types {
578         push_unique_type_name(tcx, type_parameter, output);
579         output.push_str(", ");
580     }
581
582     for projection in projections {
583         let projection = projection.skip_binder();
584         let name = &projection.projection_ty.item_name.as_str();
585         output.push_str(name);
586         output.push_str("=");
587         push_unique_type_name(tcx, projection.ty, output);
588         output.push_str(", ");
589     }
590
591     output.pop();
592     output.pop();
593
594     output.push('>');
595 }
596
597 fn push_instance_as_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
598                                      instance: Instance<'tcx>,
599                                      output: &mut String) {
600     push_item_name(tcx, instance.def, output);
601     push_type_params(tcx, &instance.substs.types, &[], output);
602 }
603
604 pub fn def_id_to_string(tcx: TyCtxt, def_id: DefId) -> String {
605     let mut output = String::new();
606     push_item_name(tcx, def_id, &mut output);
607     output
608 }
609
610 pub fn type_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
611                                 ty: ty::Ty<'tcx>)
612                                 -> String {
613     let mut output = String::new();
614     push_unique_type_name(tcx, ty, &mut output);
615     output
616 }