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