1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// 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.

//! Walks the crate looking for items/impl-items/trait-items that have
//! either a `rustc_symbol_name` or `rustc_item_path` attribute and
//! generates an error giving, respectively, the symbol name or
//! item-path. This is used for unit testing the code that generates
//! paths etc in all kinds of annoying scenarios.

use asm;
use attributes;
use base;
use consts;
use context::CodegenCx;
use declare;
use llvm;
use monomorphize::Instance;
use type_of::LayoutLlvmExt;
use rustc::hir;
use rustc::hir::def::Def;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::mir::mono::{Linkage, Visibility};
use rustc::ty::TypeFoldable;
use rustc::ty::layout::LayoutOf;
use std::fmt;

pub use rustc::mir::mono::MonoItem;

pub use rustc_mir::monomorphize::item::MonoItemExt as BaseMonoItemExt;

pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> {
    fn define(&self, cx: &CodegenCx<'a, 'tcx>) {
        debug!("BEGIN IMPLEMENTING '{} ({})' in cgu {}",
               self.to_string(cx.tcx),
               self.to_raw_string(),
               cx.codegen_unit.name());

        match *self.as_mono_item() {
            MonoItem::Static(def_id) => {
                let tcx = cx.tcx;
                let is_mutable = match tcx.describe_def(def_id) {
                    Some(Def::Static(_, is_mutable)) => is_mutable,
                    Some(other) => {
                        bug!("Expected Def::Static, found {:?}", other)
                    }
                    None => {
                        bug!("Expected Def::Static for {:?}, found nothing", def_id)
                    }
                };
                consts::codegen_static(&cx, def_id, is_mutable);
            }
            MonoItem::GlobalAsm(node_id) => {
                let item = cx.tcx.hir.expect_item(node_id);
                if let hir::ItemKind::GlobalAsm(ref ga) = item.node {
                    asm::codegen_global_asm(cx, ga);
                } else {
                    span_bug!(item.span, "Mismatch between hir::Item type and MonoItem type")
                }
            }
            MonoItem::Fn(instance) => {
                base::codegen_instance(&cx, instance);
            }
        }

        debug!("END IMPLEMENTING '{} ({})' in cgu {}",
               self.to_string(cx.tcx),
               self.to_raw_string(),
               cx.codegen_unit.name());
    }

    fn predefine(&self,
                 cx: &CodegenCx<'a, 'tcx>,
                 linkage: Linkage,
                 visibility: Visibility) {
        debug!("BEGIN PREDEFINING '{} ({})' in cgu {}",
               self.to_string(cx.tcx),
               self.to_raw_string(),
               cx.codegen_unit.name());

        let symbol_name = self.symbol_name(cx.tcx).as_str();

        debug!("symbol {}", &symbol_name);

        match *self.as_mono_item() {
            MonoItem::Static(def_id) => {
                predefine_static(cx, def_id, linkage, visibility, &symbol_name);
            }
            MonoItem::Fn(instance) => {
                predefine_fn(cx, instance, linkage, visibility, &symbol_name);
            }
            MonoItem::GlobalAsm(..) => {}
        }

        debug!("END PREDEFINING '{} ({})' in cgu {}",
               self.to_string(cx.tcx),
               self.to_raw_string(),
               cx.codegen_unit.name());
    }

    fn to_raw_string(&self) -> String {
        match *self.as_mono_item() {
            MonoItem::Fn(instance) => {
                format!("Fn({:?}, {})",
                         instance.def,
                         instance.substs.as_ptr() as usize)
            }
            MonoItem::Static(id) => {
                format!("Static({:?})", id)
            }
            MonoItem::GlobalAsm(id) => {
                format!("GlobalAsm({:?})", id)
            }
        }
    }
}

impl<'a, 'tcx> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {}

fn predefine_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
                              def_id: DefId,
                              linkage: Linkage,
                              visibility: Visibility,
                              symbol_name: &str) {
    let instance = Instance::mono(cx.tcx, def_id);
    let ty = instance.ty(cx.tcx);
    let llty = cx.layout_of(ty).llvm_type(cx);

    let g = declare::define_global(cx, symbol_name, llty).unwrap_or_else(|| {
        cx.sess().span_fatal(cx.tcx.def_span(def_id),
            &format!("symbol `{}` is already defined", symbol_name))
    });

    unsafe {
        llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage));
        llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility));
    }

    cx.instances.borrow_mut().insert(instance, g);
}

fn predefine_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
                          instance: Instance<'tcx>,
                          linkage: Linkage,
                          visibility: Visibility,
                          symbol_name: &str) {
    assert!(!instance.substs.needs_infer() &&
            !instance.substs.has_param_types());

    let mono_ty = instance.ty(cx.tcx);
    let attrs = cx.tcx.codegen_fn_attrs(instance.def_id());
    let lldecl = declare::declare_fn(cx, symbol_name, mono_ty);
    unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) };
    base::set_link_section(lldecl, &attrs);
    if linkage == Linkage::LinkOnceODR ||
        linkage == Linkage::WeakODR {
        llvm::SetUniqueComdat(cx.llmod, lldecl);
    }

    // If we're compiling the compiler-builtins crate, e.g. the equivalent of
    // compiler-rt, then we want to implicitly compile everything with hidden
    // visibility as we're going to link this object all over the place but
    // don't want the symbols to get exported.
    if linkage != Linkage::Internal && linkage != Linkage::Private &&
       cx.tcx.is_compiler_builtins(LOCAL_CRATE) {
        unsafe {
            llvm::LLVMRustSetVisibility(lldecl, llvm::Visibility::Hidden);
        }
    } else {
        unsafe {
            llvm::LLVMRustSetVisibility(lldecl, base::visibility_to_llvm(visibility));
        }
    }

    debug!("predefine_fn: mono_ty = {:?} instance = {:?}", mono_ty, instance);
    if instance.def.is_inline(cx.tcx) {
        attributes::inline(cx, lldecl, attributes::InlineAttr::Hint);
    }
    attributes::from_fn_attrs(cx, lldecl, Some(instance.def.def_id()));

    cx.instances.borrow_mut().insert(instance, lldecl);
}