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.
17 use monomorphize
::Instance
;
19 use rustc
::hir
::def_id
::DefId
;
20 use rustc
::session
::config
::OptLevel
;
21 use rustc
::ty
::{self, Ty, TyCtxt}
;
22 use rustc
::ty
::subst
::Substs
;
24 use syntax
::attr
::InlineAttr
;
25 use std
::fmt
::{self, Write}
;
27 use rustc
::mir
::mono
::Linkage
;
28 use syntax_pos
::symbol
::Symbol
;
29 use syntax
::codemap
::Span
;
30 pub use rustc
::mir
::mono
::MonoItem
;
32 /// Describes how a translation item will be instantiated in object files.
33 #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
34 pub enum InstantiationMode
{
35 /// There will be exactly one instance of the given MonoItem. It will have
36 /// external linkage so that it can be linked to from other codegen units.
38 /// In some compilation scenarios we may decide to take functions that
39 /// are typically `LocalCopy` and instead move them to `GloballyShared`
40 /// to avoid translating them a bunch of times. In this situation,
41 /// however, our local copy may conflict with other crates also
42 /// inlining the same function.
44 /// This flag indicates that this situation is occurring, and informs
45 /// symbol name calculation that some extra mangling is needed to
46 /// avoid conflicts. Note that this may eventually go away entirely if
47 /// ThinLTO enables us to *always* have a globally shared instance of a
48 /// function within one crate's compilation.
52 /// Each codegen unit containing a reference to the given MonoItem will
53 /// have its own private copy of the function (with internal linkage).
57 pub trait MonoItemExt
<'a
, 'tcx
>: fmt
::Debug
{
58 fn as_mono_item(&self) -> &MonoItem
<'tcx
>;
60 fn is_generic_fn(&self) -> bool
{
61 match *self.as_mono_item() {
62 MonoItem
::Fn(ref instance
) => {
63 instance
.substs
.types().next().is_some()
65 MonoItem
::Static(..) |
66 MonoItem
::GlobalAsm(..) => false,
70 fn symbol_name(&self, tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>) -> ty
::SymbolName
{
71 match *self.as_mono_item() {
72 MonoItem
::Fn(instance
) => tcx
.symbol_name(instance
),
73 MonoItem
::Static(def_id
) => {
74 tcx
.symbol_name(Instance
::mono(tcx
, def_id
))
76 MonoItem
::GlobalAsm(node_id
) => {
77 let def_id
= tcx
.hir
.local_def_id(node_id
);
79 name
: Symbol
::intern(&format
!("global_asm_{:?}", def_id
)).as_interned_str()
84 fn instantiation_mode(&self,
85 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>)
86 -> InstantiationMode
{
87 let inline_in_all_cgus
=
88 tcx
.sess
.opts
.debugging_opts
.inline_in_all_cgus
.unwrap_or_else(|| {
89 tcx
.sess
.opts
.optimize
!= OptLevel
::No
90 }) && !tcx
.sess
.opts
.cg
.link_dead_code
;
92 match *self.as_mono_item() {
93 MonoItem
::Fn(ref instance
) => {
95 tcx
.sess
.entry_fn
.borrow().map(|(id
, _
, _
)| tcx
.hir
.local_def_id(id
));
96 // If this function isn't inlined or otherwise has explicit
97 // linkage, then we'll be creating a globally shared version.
98 if self.explicit_linkage(tcx
).is_some() ||
99 !instance
.def
.requires_local(tcx
) ||
100 Some(instance
.def_id()) == entry_def_id
102 return InstantiationMode
::GloballyShared { may_conflict: false }
105 // At this point we don't have explicit linkage and we're an
106 // inlined function. If we're inlining into all CGUs then we'll
107 // be creating a local copy per CGU
108 if inline_in_all_cgus
{
109 return InstantiationMode
::LocalCopy
112 // Finally, if this is `#[inline(always)]` we're sure to respect
113 // that with an inline copy per CGU, but otherwise we'll be
114 // creating one copy of this `#[inline]` function which may
115 // conflict with upstream crates as it could be an exported
117 match tcx
.trans_fn_attrs(instance
.def_id()).inline
{
118 InlineAttr
::Always
=> InstantiationMode
::LocalCopy
,
120 InstantiationMode
::GloballyShared { may_conflict: true }
124 MonoItem
::Static(..) => {
125 InstantiationMode
::GloballyShared { may_conflict: false }
127 MonoItem
::GlobalAsm(..) => {
128 InstantiationMode
::GloballyShared { may_conflict: false }
133 fn explicit_linkage(&self, tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>) -> Option
<Linkage
> {
134 let def_id
= match *self.as_mono_item() {
135 MonoItem
::Fn(ref instance
) => instance
.def_id(),
136 MonoItem
::Static(def_id
) => def_id
,
137 MonoItem
::GlobalAsm(..) => return None
,
140 let trans_fn_attrs
= tcx
.trans_fn_attrs(def_id
);
141 trans_fn_attrs
.linkage
144 /// Returns whether this instance is instantiable - whether it has no unsatisfied
147 /// In order to translate an item, all of its predicates must hold, because
148 /// otherwise the item does not make sense. Type-checking ensures that
149 /// the predicates of every item that is *used by* a valid item *do*
150 /// hold, so we can rely on that.
152 /// However, we translate collector roots (reachable items) and functions
153 /// in vtables when they are seen, even if they are not used, and so they
154 /// might not be instantiable. For example, a programmer can define this
157 /// pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone {
158 /// <&mut () as Clone>::clone(&s);
161 /// That function can't be translated, because the method `<&mut () as Clone>::clone`
162 /// does not exist. Luckily for us, that function can't ever be used,
163 /// because that would require for `&'a mut (): Clone` to hold, so we
164 /// can just not emit any code, or even a linker reference for it.
166 /// Similarly, if a vtable method has such a signature, and therefore can't
167 /// be used, we can just not emit it and have a placeholder (a null pointer,
168 /// which will never be accessed) in its place.
169 fn is_instantiable(&self, tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>) -> bool
{
170 debug
!("is_instantiable({:?})", self);
171 let (def_id
, substs
) = match *self.as_mono_item() {
172 MonoItem
::Fn(ref instance
) => (instance
.def_id(), instance
.substs
),
173 MonoItem
::Static(def_id
) => (def_id
, Substs
::empty()),
174 // global asm never has predicates
175 MonoItem
::GlobalAsm(..) => return true
178 tcx
.substitute_normalize_and_test_predicates((def_id
, &substs
))
181 fn to_string(&self, tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>) -> String
{
182 return match *self.as_mono_item() {
183 MonoItem
::Fn(instance
) => {
184 to_string_internal(tcx
, "fn ", instance
)
186 MonoItem
::Static(def_id
) => {
187 let instance
= Instance
::new(def_id
, tcx
.intern_substs(&[]));
188 to_string_internal(tcx
, "static ", instance
)
190 MonoItem
::GlobalAsm(..) => {
191 "global_asm".to_string()
195 fn to_string_internal
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
197 instance
: Instance
<'tcx
>)
199 let mut result
= String
::with_capacity(32);
200 result
.push_str(prefix
);
201 let printer
= DefPathBasedNames
::new(tcx
, false, false);
202 printer
.push_instance_as_string(instance
, &mut result
);
207 fn local_span(&self, tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>) -> Option
<Span
> {
208 match *self.as_mono_item() {
209 MonoItem
::Fn(Instance { def, .. }
) => {
210 tcx
.hir
.as_local_node_id(def
.def_id())
212 MonoItem
::Static(def_id
) => {
213 tcx
.hir
.as_local_node_id(def_id
)
215 MonoItem
::GlobalAsm(node_id
) => {
218 }.map(|node_id
| tcx
.hir
.span(node_id
))
222 impl<'a
, 'tcx
> MonoItemExt
<'a
, 'tcx
> for MonoItem
<'tcx
> {
223 fn as_mono_item(&self) -> &MonoItem
<'tcx
> {
228 //=-----------------------------------------------------------------------------
229 // MonoItem String Keys
230 //=-----------------------------------------------------------------------------
232 // The code below allows for producing a unique string key for a trans item.
233 // These keys are used by the handwritten auto-tests, so they need to be
234 // predictable and human-readable.
236 // Note: A lot of this could looks very similar to what's already in the
237 // ppaux module. It would be good to refactor things so we only have one
238 // parameterizable implementation for printing types.
240 /// Same as `unique_type_name()` but with the result pushed onto the given
241 /// `output` parameter.
242 pub struct DefPathBasedNames
<'a
, 'tcx
: 'a
> {
243 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
244 omit_disambiguators
: bool
,
245 omit_local_crate_name
: bool
,
248 impl<'a
, 'tcx
> DefPathBasedNames
<'a
, 'tcx
> {
249 pub fn new(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
250 omit_disambiguators
: bool
,
251 omit_local_crate_name
: bool
)
256 omit_local_crate_name
,
260 pub fn push_type_name(&self, t
: Ty
<'tcx
>, output
: &mut String
) {
262 ty
::TyBool
=> output
.push_str("bool"),
263 ty
::TyChar
=> output
.push_str("char"),
264 ty
::TyStr
=> output
.push_str("str"),
265 ty
::TyNever
=> output
.push_str("!"),
266 ty
::TyInt(ast
::IntTy
::Isize
) => output
.push_str("isize"),
267 ty
::TyInt(ast
::IntTy
::I8
) => output
.push_str("i8"),
268 ty
::TyInt(ast
::IntTy
::I16
) => output
.push_str("i16"),
269 ty
::TyInt(ast
::IntTy
::I32
) => output
.push_str("i32"),
270 ty
::TyInt(ast
::IntTy
::I64
) => output
.push_str("i64"),
271 ty
::TyInt(ast
::IntTy
::I128
) => output
.push_str("i128"),
272 ty
::TyUint(ast
::UintTy
::Usize
) => output
.push_str("usize"),
273 ty
::TyUint(ast
::UintTy
::U8
) => output
.push_str("u8"),
274 ty
::TyUint(ast
::UintTy
::U16
) => output
.push_str("u16"),
275 ty
::TyUint(ast
::UintTy
::U32
) => output
.push_str("u32"),
276 ty
::TyUint(ast
::UintTy
::U64
) => output
.push_str("u64"),
277 ty
::TyUint(ast
::UintTy
::U128
) => output
.push_str("u128"),
278 ty
::TyFloat(ast
::FloatTy
::F32
) => output
.push_str("f32"),
279 ty
::TyFloat(ast
::FloatTy
::F64
) => output
.push_str("f64"),
280 ty
::TyAdt(adt_def
, substs
) => {
281 self.push_def_path(adt_def
.did
, output
);
282 self.push_type_params(substs
, iter
::empty(), output
);
284 ty
::TyTuple(component_types
) => {
286 for &component_type
in component_types
{
287 self.push_type_name(component_type
, output
);
288 output
.push_str(", ");
290 if !component_types
.is_empty() {
296 ty
::TyRawPtr(ty
::TypeAndMut { ty: inner_type, mutbl }
) => {
299 hir
::MutImmutable
=> output
.push_str("const "),
300 hir
::MutMutable
=> output
.push_str("mut "),
303 self.push_type_name(inner_type
, output
);
305 ty
::TyRef(_
, ty
::TypeAndMut { ty: inner_type, mutbl }
) => {
307 if mutbl
== hir
::MutMutable
{
308 output
.push_str("mut ");
311 self.push_type_name(inner_type
, output
);
313 ty
::TyArray(inner_type
, len
) => {
315 self.push_type_name(inner_type
, output
);
316 write
!(output
, "; {}",
317 len
.val
.unwrap_u64()).unwrap();
320 ty
::TySlice(inner_type
) => {
322 self.push_type_name(inner_type
, output
);
325 ty
::TyDynamic(ref trait_data
, ..) => {
326 if let Some(principal
) = trait_data
.principal() {
327 self.push_def_path(principal
.def_id(), output
);
328 self.push_type_params(principal
.skip_binder().substs
,
329 trait_data
.projection_bounds(),
333 ty
::TyForeign(did
) => self.push_def_path(did
, output
),
336 let sig
= t
.fn_sig(self.tcx
);
337 if sig
.unsafety() == hir
::Unsafety
::Unsafe
{
338 output
.push_str("unsafe ");
342 if abi
!= ::rustc_target
::spec
::abi
::Abi
::Rust
{
343 output
.push_str("extern \"");
344 output
.push_str(abi
.name());
345 output
.push_str("\" ");
348 output
.push_str("fn(");
350 let sig
= self.tcx
.normalize_erasing_late_bound_regions(
351 ty
::ParamEnv
::reveal_all(),
355 if !sig
.inputs().is_empty() {
356 for ¶meter_type
in sig
.inputs() {
357 self.push_type_name(parameter_type
, output
);
358 output
.push_str(", ");
365 if !sig
.inputs().is_empty() {
366 output
.push_str(", ...");
368 output
.push_str("...");
374 if !sig
.output().is_nil() {
375 output
.push_str(" -> ");
376 self.push_type_name(sig
.output(), output
);
379 ty
::TyGenerator(def_id
, ref closure_substs
, _
) |
380 ty
::TyClosure(def_id
, ref closure_substs
) => {
381 self.push_def_path(def_id
, output
);
382 let generics
= self.tcx
.generics_of(self.tcx
.closure_base_def_id(def_id
));
383 let substs
= closure_substs
.substs
.truncate_to(self.tcx
, generics
);
384 self.push_type_params(substs
, iter
::empty(), output
);
388 ty
::TyProjection(..) |
390 ty
::TyGeneratorWitness(_
) |
392 bug
!("DefPathBasedNames: Trying to create type name for \
393 unexpected type: {:?}", t
);
398 pub fn push_def_path(&self,
400 output
: &mut String
) {
401 let def_path
= self.tcx
.def_path(def_id
);
404 if !(self.omit_local_crate_name
&& def_id
.is_local()) {
405 output
.push_str(&self.tcx
.crate_name(def_path
.krate
).as_str());
406 output
.push_str("::");
409 // foo::bar::ItemName::
410 for part
in self.tcx
.def_path(def_id
).data
{
411 if self.omit_disambiguators
{
412 write
!(output
, "{}::", part
.data
.as_interned_str()).unwrap();
414 write
!(output
, "{}[{}]::",
415 part
.data
.as_interned_str(),
416 part
.disambiguator
).unwrap();
425 fn push_type_params
<I
>(&self,
426 substs
: &Substs
<'tcx
>,
429 where I
: Iterator
<Item
=ty
::PolyExistentialProjection
<'tcx
>>
431 let mut projections
= projections
.peekable();
432 if substs
.types().next().is_none() && projections
.peek().is_none() {
438 for type_parameter
in substs
.types() {
439 self.push_type_name(type_parameter
, output
);
440 output
.push_str(", ");
443 for projection
in projections
{
444 let projection
= projection
.skip_binder();
445 let name
= &self.tcx
.associated_item(projection
.item_def_id
).name
.as_str();
446 output
.push_str(name
);
447 output
.push_str("=");
448 self.push_type_name(projection
.ty
, output
);
449 output
.push_str(", ");
458 pub fn push_instance_as_string(&self,
459 instance
: Instance
<'tcx
>,
460 output
: &mut String
) {
461 self.push_def_path(instance
.def_id(), output
);
462 self.push_type_params(instance
.substs
, iter
::empty(), output
);