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.
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.
11 use context::SharedCrateContext;
12 use monomorphize::Instance;
13 use rustc::ty::TyCtxt;
15 use syntax::codemap::Span;
16 use trans_item::TransItem;
17 use util::nodemap::FxHashMap;
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.
24 pub struct SymbolMap<'tcx> {
25 index: FxHashMap<TransItem<'tcx>, (usize, usize)>,
29 impl<'tcx> SymbolMap<'tcx> {
31 pub fn build<'a, I>(scx: &SharedCrateContext<'a, 'tcx>,
34 where I: Iterator<Item=TransItem<'tcx>>
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))
41 (&mut symbols[..]).sort_by(|&(_, ref sym1), &(_, ref sym2)|{
45 for pair in (&symbols[..]).windows(2) {
46 let sym1 = &pair[0].1;
47 let sym2 = &pair[1].1;
50 let trans_item1 = pair[0].0;
51 let trans_item2 = pair[1].0;
53 let span1 = get_span(scx.tcx(), trans_item1);
54 let span2 = get_span(scx.tcx(), trans_item2);
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 {
66 (None, Some(span)) => Some(span),
70 let error_message = format!("symbol `{}` is already defined", sym1);
72 if let Some(span) = span {
73 scx.sess().span_fatal(span, &error_message)
75 scx.sess().fatal(&error_message)
80 let mut symbol_map = SymbolMap {
82 arena: String::with_capacity(1024),
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?")
96 fn get_span<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
97 trans_item: TransItem<'tcx>) -> Option<Span> {
99 TransItem::Fn(Instance { def, .. }) => {
100 tcx.hir.as_local_node_id(def.def_id())
102 TransItem::Static(node_id) |
103 TransItem::GlobalAsm(node_id) => {
107 tcx.hir.span(node_id)
114 pub fn get(&self, trans_item: TransItem<'tcx>) -> Option<&str> {
115 self.index.get(&trans_item).map(|&(start_index, end_index)| {
116 &self.arena[start_index .. end_index]
120 pub fn get_or_compute<'map, 'scx>(&'map self,
121 scx: &SharedCrateContext<'scx, 'tcx>,
122 trans_item: TransItem<'tcx>)
124 if let Some(sym) = self.get(trans_item) {
127 Cow::from(trans_item.compute_symbol_name(scx))