+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use context::SharedCrateContext;
+use monomorphize::Instance;
+use rustc::ty::TyCtxt;
+use syntax::codemap::Span;
+use trans_item::TransItem;
+use util::nodemap::FnvHashMap;
+
+
+// In the SymbolMap we collect the symbol names of all translation items of
+// the current crate.
+
+pub struct SymbolMap<'tcx> {
+ index: FnvHashMap<TransItem<'tcx>, (usize, usize)>,
+ arena: String,
+}
+
+impl<'tcx> SymbolMap<'tcx> {
+
+ pub fn build<'a, I>(scx: &SharedCrateContext<'a, 'tcx>,
+ trans_items: I)
+ -> SymbolMap<'tcx>
+ where I: Iterator<Item=TransItem<'tcx>>
+ {
+ // Check for duplicate symbol names
+ let mut symbols: Vec<_> = trans_items.map(|trans_item| {
+ (trans_item, trans_item.compute_symbol_name(scx))
+ }).collect();
+
+ (&mut symbols[..]).sort_by(|&(_, ref sym1), &(_, ref sym2)|{
+ sym1.cmp(sym2)
+ });
+
+ for pair in (&symbols[..]).windows(2) {
+ let sym1 = &pair[0].1;
+ let sym2 = &pair[1].1;
+
+ if *sym1 == *sym2 {
+ let trans_item1 = pair[0].0;
+ let trans_item2 = pair[1].0;
+
+ let span1 = get_span(scx.tcx(), trans_item1);
+ let span2 = get_span(scx.tcx(), trans_item2);
+
+ // Deterministically select one of the spans for error reporting
+ let span = match (span1, span2) {
+ (Some(span1), Some(span2)) => {
+ Some(if span1.lo.0 > span2.lo.0 {
+ span1
+ } else {
+ span2
+ })
+ }
+ (Some(span), None) |
+ (None, Some(span)) => Some(span),
+ _ => None
+ };
+
+ let error_message = format!("symbol `{}` is already defined", sym1);
+
+ if let Some(span) = span {
+ scx.sess().span_fatal(span, &error_message)
+ } else {
+ scx.sess().fatal(&error_message)
+ }
+ }
+ }
+
+ let mut symbol_map = SymbolMap {
+ index: FnvHashMap(),
+ arena: String::with_capacity(1024),
+ };
+
+ for (trans_item, symbol) in symbols {
+ let start_index = symbol_map.arena.len();
+ symbol_map.arena.push_str(&symbol[..]);
+ let end_index = symbol_map.arena.len();
+ let prev_entry = symbol_map.index.insert(trans_item,
+ (start_index, end_index));
+ if prev_entry.is_some() {
+ bug!("TransItem encountered twice?")
+ }
+ }
+
+ fn get_span<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ trans_item: TransItem<'tcx>) -> Option<Span> {
+ match trans_item {
+ TransItem::Fn(Instance { def, .. }) => {
+ tcx.map.as_local_node_id(def)
+ }
+ TransItem::Static(node_id) => Some(node_id),
+ TransItem::DropGlue(_) => None,
+ }.map(|node_id| {
+ tcx.map.span(node_id)
+ })
+ }
+
+ symbol_map
+ }
+
+ pub fn get(&self, trans_item: TransItem<'tcx>) -> Option<&str> {
+ self.index.get(&trans_item).map(|&(start_index, end_index)| {
+ &self.arena[start_index .. end_index]
+ })
+ }
+}