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