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 //! 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.
20 use context
::{CrateContext, SharedCrateContext}
;
23 use glue
::DropGlueKind
;
25 use monomorphize
::{self, Instance}
;
26 use rustc
::dep_graph
::DepNode
;
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}
;
36 use abi
::{Abi, FnType}
;
37 use back
::symbol_names
;
41 #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
42 pub enum TransItem
<'tcx
> {
43 DropGlue(DropGlueKind
<'tcx
>),
48 /// Describes how a translation item will be instantiated in object files.
49 #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
50 pub enum InstantiationMode
{
51 /// There will be exactly one instance of the given TransItem. It will have
52 /// external linkage so that it can be linked to from other codegen units.
55 /// Each codegen unit containing a reference to the given TransItem will
56 /// have its own private copy of the function (with internal linkage).
60 impl<'a
, 'tcx
> TransItem
<'tcx
> {
62 pub fn define(&self, ccx
: &CrateContext
<'a
, 'tcx
>) {
63 debug
!("BEGIN IMPLEMENTING '{} ({})' in cgu {}",
64 self.to_string(ccx
.tcx()),
66 ccx
.codegen_unit().name());
68 // (*) This code executes in the context of a dep-node for the
69 // entire CGU. In some cases, we introduce dep-nodes for
70 // particular items that we are translating (these nodes will
71 // have read edges coming into the CGU node). These smaller
72 // nodes are not needed for correctness -- we always
73 // invalidate an entire CGU at a time -- but they enable
74 // finer-grained testing, since you can write tests that check
75 // that the incoming edges to a particular fn are from a
79 TransItem
::Static(node_id
) => {
80 let def_id
= ccx
.tcx().hir
.local_def_id(node_id
);
81 let _task
= ccx
.tcx().dep_graph
.in_task(DepNode
::TransCrateItem(def_id
)); // (*)
82 let item
= ccx
.tcx().hir
.expect_item(node_id
);
83 if let hir
::ItemStatic(_
, m
, _
) = item
.node
{
84 match consts
::trans_static(&ccx
, m
, item
.id
, &item
.attrs
) {
85 Ok(_
) => { /* Cool, everything's alright. */ }
,
87 // FIXME: shouldn't this be a `span_err`?
89 ccx
.tcx(), &err
, item
.span
, "static");
93 span_bug
!(item
.span
, "Mismatch between hir::Item type and TransItem type")
96 TransItem
::Fn(instance
) => {
97 let _task
= ccx
.tcx().dep_graph
.in_task(
98 DepNode
::TransCrateItem(instance
.def
)); // (*)
100 base
::trans_instance(&ccx
, instance
);
102 TransItem
::DropGlue(dg
) => {
103 glue
::implement_drop_glue(&ccx
, dg
);
107 debug
!("END IMPLEMENTING '{} ({})' in cgu {}",
108 self.to_string(ccx
.tcx()),
109 self.to_raw_string(),
110 ccx
.codegen_unit().name());
113 pub fn predefine(&self,
114 ccx
: &CrateContext
<'a
, 'tcx
>,
115 linkage
: llvm
::Linkage
) {
116 debug
!("BEGIN PREDEFINING '{} ({})' in cgu {}",
117 self.to_string(ccx
.tcx()),
118 self.to_raw_string(),
119 ccx
.codegen_unit().name());
121 let symbol_name
= ccx
.symbol_map()
122 .get_or_compute(ccx
.shared(), *self);
124 debug
!("symbol {}", &symbol_name
);
127 TransItem
::Static(node_id
) => {
128 TransItem
::predefine_static(ccx
, node_id
, linkage
, &symbol_name
);
130 TransItem
::Fn(instance
) => {
131 TransItem
::predefine_fn(ccx
, instance
, linkage
, &symbol_name
);
133 TransItem
::DropGlue(dg
) => {
134 TransItem
::predefine_drop_glue(ccx
, dg
, linkage
, &symbol_name
);
138 debug
!("END PREDEFINING '{} ({})' in cgu {}",
139 self.to_string(ccx
.tcx()),
140 self.to_raw_string(),
141 ccx
.codegen_unit().name());
144 fn predefine_static(ccx
: &CrateContext
<'a
, 'tcx
>,
145 node_id
: ast
::NodeId
,
146 linkage
: llvm
::Linkage
,
148 let def_id
= ccx
.tcx().hir
.local_def_id(node_id
);
149 let ty
= ccx
.tcx().item_type(def_id
);
150 let llty
= type_of
::type_of(ccx
, ty
);
152 let g
= declare
::define_global(ccx
, symbol_name
, llty
).unwrap_or_else(|| {
153 ccx
.sess().span_fatal(ccx
.tcx().hir
.span(node_id
),
154 &format
!("symbol `{}` is already defined", symbol_name
))
157 unsafe { llvm::LLVMRustSetLinkage(g, linkage) }
;
159 let instance
= Instance
::mono(ccx
.shared(), def_id
);
160 ccx
.instances().borrow_mut().insert(instance
, g
);
161 ccx
.statics().borrow_mut().insert(g
, def_id
);
164 fn predefine_fn(ccx
: &CrateContext
<'a
, 'tcx
>,
165 instance
: Instance
<'tcx
>,
166 linkage
: llvm
::Linkage
,
168 assert
!(!instance
.substs
.needs_infer() &&
169 !instance
.substs
.has_param_types());
171 let item_ty
= ccx
.tcx().item_type(instance
.def
);
172 let item_ty
= ccx
.tcx().erase_regions(&item_ty
);
173 let mono_ty
= monomorphize
::apply_param_substs(ccx
.shared(), instance
.substs
, &item_ty
);
175 let attrs
= ccx
.tcx().get_attrs(instance
.def
);
176 let lldecl
= declare
::declare_fn(ccx
, symbol_name
, mono_ty
);
177 unsafe { llvm::LLVMRustSetLinkage(lldecl, linkage) }
;
178 base
::set_link_section(ccx
, lldecl
, &attrs
);
179 if linkage
== llvm
::Linkage
::LinkOnceODRLinkage
||
180 linkage
== llvm
::Linkage
::WeakODRLinkage
{
181 llvm
::SetUniqueComdat(ccx
.llmod(), lldecl
);
184 if let ty
::TyClosure(..) = mono_ty
.sty
{
185 // set an inline hint for all closures
186 attributes
::inline(lldecl
, attributes
::InlineAttr
::Hint
);
189 attributes
::from_fn_attrs(ccx
, &attrs
, lldecl
);
191 ccx
.instances().borrow_mut().insert(instance
, lldecl
);
194 fn predefine_drop_glue(ccx
: &CrateContext
<'a
, 'tcx
>,
195 dg
: glue
::DropGlueKind
<'tcx
>,
196 linkage
: llvm
::Linkage
,
199 assert_eq
!(dg
.ty(), glue
::get_drop_glue_type(ccx
.shared(), dg
.ty()));
202 let sig
= tcx
.mk_fn_sig(iter
::once(tcx
.mk_mut_ptr(t
)), tcx
.mk_nil(), false);
204 debug
!("predefine_drop_glue: sig={}", sig
);
206 let fn_ty
= FnType
::new(ccx
, Abi
::Rust
, &sig
, &[]);
207 let llfnty
= fn_ty
.llvm_type(ccx
);
209 assert
!(declare
::get_defined_value(ccx
, symbol_name
).is_none());
210 let llfn
= declare
::declare_cfn(ccx
, symbol_name
, llfnty
);
211 unsafe { llvm::LLVMRustSetLinkage(llfn, linkage) }
;
212 if linkage
== llvm
::Linkage
::LinkOnceODRLinkage
||
213 linkage
== llvm
::Linkage
::WeakODRLinkage
{
214 llvm
::SetUniqueComdat(ccx
.llmod(), llfn
);
216 attributes
::set_frame_pointer_elimination(ccx
, llfn
);
217 ccx
.drop_glues().borrow_mut().insert(dg
, (llfn
, fn_ty
));
220 pub fn compute_symbol_name(&self,
221 scx
: &SharedCrateContext
<'a
, 'tcx
>) -> String
{
223 TransItem
::Fn(instance
) => instance
.symbol_name(scx
),
224 TransItem
::Static(node_id
) => {
225 let def_id
= scx
.tcx().hir
.local_def_id(node_id
);
226 Instance
::mono(scx
, def_id
).symbol_name(scx
)
228 TransItem
::DropGlue(dg
) => {
229 let prefix
= match dg
{
230 DropGlueKind
::Ty(_
) => "drop",
231 DropGlueKind
::TyContents(_
) => "drop_contents",
233 symbol_names
::exported_name_from_type_and_prefix(scx
, dg
.ty(), prefix
)
238 pub fn is_from_extern_crate(&self) -> bool
{
240 TransItem
::Fn(ref instance
) => !instance
.def
.is_local(),
241 TransItem
::DropGlue(..) |
242 TransItem
::Static(..) => false,
246 pub fn instantiation_mode(&self,
247 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>)
248 -> InstantiationMode
{
250 TransItem
::Fn(ref instance
) => {
251 if self.explicit_linkage(tcx
).is_none() &&
252 (common
::is_closure(tcx
, instance
.def
) ||
253 attr
::requests_inline(&tcx
.get_attrs(instance
.def
)[..])) {
254 InstantiationMode
::LocalCopy
256 InstantiationMode
::GloballyShared
259 TransItem
::DropGlue(..) => InstantiationMode
::LocalCopy
,
260 TransItem
::Static(..) => InstantiationMode
::GloballyShared
,
264 pub fn is_generic_fn(&self) -> bool
{
266 TransItem
::Fn(ref instance
) => {
267 instance
.substs
.types().next().is_some()
269 TransItem
::DropGlue(..) |
270 TransItem
::Static(..) => false,
274 pub fn explicit_linkage(&self, tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>) -> Option
<llvm
::Linkage
> {
275 let def_id
= match *self {
276 TransItem
::Fn(ref instance
) => instance
.def
,
277 TransItem
::Static(node_id
) => tcx
.hir
.local_def_id(node_id
),
278 TransItem
::DropGlue(..) => return None
,
281 let attributes
= tcx
.get_attrs(def_id
);
282 if let Some(name
) = attr
::first_attr_value_str_by_name(&attributes
, "linkage") {
283 if let Some(linkage
) = base
::llvm_linkage_by_name(&name
.as_str()) {
286 let span
= tcx
.hir
.span_if_local(def_id
);
287 if let Some(span
) = span
{
288 tcx
.sess
.span_fatal(span
, "invalid linkage specified")
290 tcx
.sess
.fatal(&format
!("invalid linkage specified: {}", name
))
298 pub fn to_string(&self, tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>) -> String
{
299 let hir_map
= &tcx
.hir
;
302 TransItem
::DropGlue(dg
) => {
303 let mut s
= String
::with_capacity(32);
305 DropGlueKind
::Ty(_
) => s
.push_str("drop-glue "),
306 DropGlueKind
::TyContents(_
) => s
.push_str("drop-glue-contents "),
308 let printer
= DefPathBasedNames
::new(tcx
, false, false);
309 printer
.push_type_name(dg
.ty(), &mut s
);
312 TransItem
::Fn(instance
) => {
313 to_string_internal(tcx
, "fn ", instance
)
315 TransItem
::Static(node_id
) => {
316 let def_id
= hir_map
.local_def_id(node_id
);
317 let instance
= Instance
::new(def_id
, tcx
.intern_substs(&[]));
318 to_string_internal(tcx
, "static ", instance
)
322 fn to_string_internal
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
324 instance
: Instance
<'tcx
>)
326 let mut result
= String
::with_capacity(32);
327 result
.push_str(prefix
);
328 let printer
= DefPathBasedNames
::new(tcx
, false, false);
329 printer
.push_instance_as_string(instance
, &mut result
);
334 pub fn to_raw_string(&self) -> String
{
336 TransItem
::DropGlue(dg
) => {
337 let prefix
= match dg
{
338 DropGlueKind
::Ty(_
) => "Ty",
339 DropGlueKind
::TyContents(_
) => "TyContents",
341 format
!("DropGlue({}: {})", prefix
, dg
.ty() as *const _
as usize)
343 TransItem
::Fn(instance
) => {
344 format
!("Fn({:?}, {})",
346 instance
.substs
.as_ptr() as usize)
348 TransItem
::Static(id
) => {
349 format
!("Static({:?})", id
)
356 //=-----------------------------------------------------------------------------
357 // TransItem String Keys
358 //=-----------------------------------------------------------------------------
360 // The code below allows for producing a unique string key for a trans item.
361 // These keys are used by the handwritten auto-tests, so they need to be
362 // predictable and human-readable.
364 // Note: A lot of this could looks very similar to what's already in the
365 // ppaux module. It would be good to refactor things so we only have one
366 // parameterizable implementation for printing types.
368 /// Same as `unique_type_name()` but with the result pushed onto the given
369 /// `output` parameter.
370 pub struct DefPathBasedNames
<'a
, 'tcx
: 'a
> {
371 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
372 omit_disambiguators
: bool
,
373 omit_local_crate_name
: bool
,
376 impl<'a
, 'tcx
> DefPathBasedNames
<'a
, 'tcx
> {
377 pub fn new(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
378 omit_disambiguators
: bool
,
379 omit_local_crate_name
: bool
)
383 omit_disambiguators
: omit_disambiguators
,
384 omit_local_crate_name
: omit_local_crate_name
,
388 pub fn push_type_name(&self, t
: Ty
<'tcx
>, output
: &mut String
) {
390 ty
::TyBool
=> output
.push_str("bool"),
391 ty
::TyChar
=> output
.push_str("char"),
392 ty
::TyStr
=> output
.push_str("str"),
393 ty
::TyNever
=> output
.push_str("!"),
394 ty
::TyInt(ast
::IntTy
::Is
) => output
.push_str("isize"),
395 ty
::TyInt(ast
::IntTy
::I8
) => output
.push_str("i8"),
396 ty
::TyInt(ast
::IntTy
::I16
) => output
.push_str("i16"),
397 ty
::TyInt(ast
::IntTy
::I32
) => output
.push_str("i32"),
398 ty
::TyInt(ast
::IntTy
::I64
) => output
.push_str("i64"),
399 ty
::TyInt(ast
::IntTy
::I128
) => output
.push_str("i128"),
400 ty
::TyUint(ast
::UintTy
::Us
) => output
.push_str("usize"),
401 ty
::TyUint(ast
::UintTy
::U8
) => output
.push_str("u8"),
402 ty
::TyUint(ast
::UintTy
::U16
) => output
.push_str("u16"),
403 ty
::TyUint(ast
::UintTy
::U32
) => output
.push_str("u32"),
404 ty
::TyUint(ast
::UintTy
::U64
) => output
.push_str("u64"),
405 ty
::TyUint(ast
::UintTy
::U128
) => output
.push_str("u128"),
406 ty
::TyFloat(ast
::FloatTy
::F32
) => output
.push_str("f32"),
407 ty
::TyFloat(ast
::FloatTy
::F64
) => output
.push_str("f64"),
408 ty
::TyAdt(adt_def
, substs
) => {
409 self.push_def_path(adt_def
.did
, output
);
410 self.push_type_params(substs
, iter
::empty(), output
);
412 ty
::TyTuple(component_types
) => {
414 for &component_type
in component_types
{
415 self.push_type_name(component_type
, output
);
416 output
.push_str(", ");
418 if !component_types
.is_empty() {
424 ty
::TyRawPtr(ty
::TypeAndMut { ty: inner_type, mutbl }
) => {
427 hir
::MutImmutable
=> output
.push_str("const "),
428 hir
::MutMutable
=> output
.push_str("mut "),
431 self.push_type_name(inner_type
, output
);
433 ty
::TyRef(_
, ty
::TypeAndMut { ty: inner_type, mutbl }
) => {
435 if mutbl
== hir
::MutMutable
{
436 output
.push_str("mut ");
439 self.push_type_name(inner_type
, output
);
441 ty
::TyArray(inner_type
, len
) => {
443 self.push_type_name(inner_type
, output
);
444 write
!(output
, "; {}", len
).unwrap();
447 ty
::TySlice(inner_type
) => {
449 self.push_type_name(inner_type
, output
);
452 ty
::TyDynamic(ref trait_data
, ..) => {
453 if let Some(principal
) = trait_data
.principal() {
454 self.push_def_path(principal
.def_id(), output
);
455 self.push_type_params(principal
.skip_binder().substs
,
456 trait_data
.projection_bounds(),
460 ty
::TyFnDef(.., &ty
::BareFnTy{ unsafety, abi, ref sig }
) |
461 ty
::TyFnPtr(&ty
::BareFnTy{ unsafety, abi, ref sig }
) => {
462 if unsafety
== hir
::Unsafety
::Unsafe
{
463 output
.push_str("unsafe ");
466 if abi
!= ::abi
::Abi
::Rust
{
467 output
.push_str("extern \"");
468 output
.push_str(abi
.name());
469 output
.push_str("\" ");
472 output
.push_str("fn(");
474 let sig
= self.tcx
.erase_late_bound_regions_and_normalize(sig
);
476 if !sig
.inputs().is_empty() {
477 for ¶meter_type
in sig
.inputs() {
478 self.push_type_name(parameter_type
, output
);
479 output
.push_str(", ");
486 if !sig
.inputs().is_empty() {
487 output
.push_str(", ...");
489 output
.push_str("...");
495 if !sig
.output().is_nil() {
496 output
.push_str(" -> ");
497 self.push_type_name(sig
.output(), output
);
500 ty
::TyClosure(def_id
, ref closure_substs
) => {
501 self.push_def_path(def_id
, output
);
502 let generics
= self.tcx
.item_generics(self.tcx
.closure_base_def_id(def_id
));
503 let substs
= closure_substs
.substs
.truncate_to(self.tcx
, generics
);
504 self.push_type_params(substs
, iter
::empty(), output
);
508 ty
::TyProjection(..) |
511 bug
!("DefPathBasedNames: Trying to create type name for \
512 unexpected type: {:?}", t
);
517 pub fn push_def_path(&self,
519 output
: &mut String
) {
520 let def_path
= self.tcx
.def_path(def_id
);
523 if !(self.omit_local_crate_name
&& def_id
.is_local()) {
524 output
.push_str(&self.tcx
.crate_name(def_path
.krate
).as_str());
525 output
.push_str("::");
528 // foo::bar::ItemName::
529 for part
in self.tcx
.def_path(def_id
).data
{
530 if self.omit_disambiguators
{
531 write
!(output
, "{}::", part
.data
.as_interned_str()).unwrap();
533 write
!(output
, "{}[{}]::",
534 part
.data
.as_interned_str(),
535 part
.disambiguator
).unwrap();
544 fn push_type_params
<I
>(&self,
545 substs
: &Substs
<'tcx
>,
548 where I
: Iterator
<Item
=ty
::PolyExistentialProjection
<'tcx
>>
550 let mut projections
= projections
.peekable();
551 if substs
.types().next().is_none() && projections
.peek().is_none() {
557 for type_parameter
in substs
.types() {
558 self.push_type_name(type_parameter
, output
);
559 output
.push_str(", ");
562 for projection
in projections
{
563 let projection
= projection
.skip_binder();
564 let name
= &projection
.item_name
.as_str();
565 output
.push_str(name
);
566 output
.push_str("=");
567 self.push_type_name(projection
.ty
, output
);
568 output
.push_str(", ");
577 pub fn push_instance_as_string(&self,
578 instance
: Instance
<'tcx
>,
579 output
: &mut String
) {
580 self.push_def_path(instance
.def
, output
);
581 self.push_type_params(instance
.substs
, iter
::empty(), output
);