]> git.proxmox.com Git - rustc.git/blob - src/librustc_trans/symbol_map.rs
New upstream version 1.12.0+dfsg1
[rustc.git] / src / librustc_trans / symbol_map.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 use context::SharedCrateContext;
12 use monomorphize::Instance;
13 use rustc::ty::TyCtxt;
14 use std::borrow::Cow;
15 use syntax::codemap::Span;
16 use trans_item::TransItem;
17 use util::nodemap::FnvHashMap;
18
19 // In the SymbolMap we collect the symbol names of all translation items of
20 // the current crate. This map exists as a performance optimization. Symbol
21 // names of translation items are deterministic and fully defined by the item.
22 // Thus they could also always be recomputed if needed.
23
24 pub struct SymbolMap<'tcx> {
25 index: FnvHashMap<TransItem<'tcx>, (usize, usize)>,
26 arena: String,
27 }
28
29 impl<'tcx> SymbolMap<'tcx> {
30
31 pub fn build<'a, I>(scx: &SharedCrateContext<'a, 'tcx>,
32 trans_items: I)
33 -> SymbolMap<'tcx>
34 where I: Iterator<Item=TransItem<'tcx>>
35 {
36 // Check for duplicate symbol names
37 let mut symbols: Vec<_> = trans_items.map(|trans_item| {
38 (trans_item, trans_item.compute_symbol_name(scx))
39 }).collect();
40
41 (&mut symbols[..]).sort_by(|&(_, ref sym1), &(_, ref sym2)|{
42 sym1.cmp(sym2)
43 });
44
45 for pair in (&symbols[..]).windows(2) {
46 let sym1 = &pair[0].1;
47 let sym2 = &pair[1].1;
48
49 if *sym1 == *sym2 {
50 let trans_item1 = pair[0].0;
51 let trans_item2 = pair[1].0;
52
53 let span1 = get_span(scx.tcx(), trans_item1);
54 let span2 = get_span(scx.tcx(), trans_item2);
55
56 // Deterministically select one of the spans for error reporting
57 let span = match (span1, span2) {
58 (Some(span1), Some(span2)) => {
59 Some(if span1.lo.0 > span2.lo.0 {
60 span1
61 } else {
62 span2
63 })
64 }
65 (Some(span), None) |
66 (None, Some(span)) => Some(span),
67 _ => None
68 };
69
70 let error_message = format!("symbol `{}` is already defined", sym1);
71
72 if let Some(span) = span {
73 scx.sess().span_fatal(span, &error_message)
74 } else {
75 scx.sess().fatal(&error_message)
76 }
77 }
78 }
79
80 let mut symbol_map = SymbolMap {
81 index: FnvHashMap(),
82 arena: String::with_capacity(1024),
83 };
84
85 for (trans_item, symbol) in symbols {
86 let start_index = symbol_map.arena.len();
87 symbol_map.arena.push_str(&symbol[..]);
88 let end_index = symbol_map.arena.len();
89 let prev_entry = symbol_map.index.insert(trans_item,
90 (start_index, end_index));
91 if prev_entry.is_some() {
92 bug!("TransItem encountered twice?")
93 }
94 }
95
96 fn get_span<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
97 trans_item: TransItem<'tcx>) -> Option<Span> {
98 match trans_item {
99 TransItem::Fn(Instance { def, .. }) => {
100 tcx.map.as_local_node_id(def)
101 }
102 TransItem::Static(node_id) => Some(node_id),
103 TransItem::DropGlue(_) => None,
104 }.map(|node_id| {
105 tcx.map.span(node_id)
106 })
107 }
108
109 symbol_map
110 }
111
112 pub fn get(&self, trans_item: TransItem<'tcx>) -> Option<&str> {
113 self.index.get(&trans_item).map(|&(start_index, end_index)| {
114 &self.arena[start_index .. end_index]
115 })
116 }
117
118 pub fn get_or_compute<'map, 'scx>(&'map self,
119 scx: &SharedCrateContext<'scx, 'tcx>,
120 trans_item: TransItem<'tcx>)
121 -> Cow<'map, str> {
122 if let Some(sym) = self.get(trans_item) {
123 Cow::from(sym)
124 } else {
125 Cow::from(trans_item.compute_symbol_name(scx))
126 }
127 }
128 }