]> git.proxmox.com Git - rustc.git/blame - src/librustc_trans/trans_item.rs
Imported Upstream version 1.11.0+dfsg1
[rustc.git] / src / librustc_trans / trans_item.rs
CommitLineData
a7813a04
XL
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.
4//
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.
10
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.
16
17use base::llvm_linkage_by_name;
18use glue::DropGlueKind;
19use llvm;
20use monomorphize::Instance;
21use rustc::hir;
22use rustc::hir::def_id::DefId;
23use rustc::ty::{self, Ty, TyCtxt};
24use rustc::ty::subst;
25use std::hash::{Hash, Hasher};
26use syntax::ast::{self, NodeId};
27use syntax::attr;
28use syntax::parse::token;
29
30#[derive(PartialEq, Eq, Clone, Copy, Debug)]
31pub enum TransItem<'tcx> {
32 DropGlue(DropGlueKind<'tcx>),
33 Fn(Instance<'tcx>),
34 Static(NodeId)
35}
36
37impl<'tcx> Hash for TransItem<'tcx> {
38 fn hash<H: Hasher>(&self, s: &mut H) {
39 match *self {
40 TransItem::DropGlue(t) => {
41 0u8.hash(s);
42 t.hash(s);
43 },
44 TransItem::Fn(instance) => {
45 1u8.hash(s);
46 instance.def.hash(s);
47 (instance.substs as *const _ as usize).hash(s);
48 }
49 TransItem::Static(node_id) => {
50 2u8.hash(s);
51 node_id.hash(s);
52 }
53 };
54 }
55}
56
57//=-----------------------------------------------------------------------------
58// TransItem String Keys
59//=-----------------------------------------------------------------------------
60
61// The code below allows for producing a unique string key for a trans item.
62// These keys are used by the handwritten auto-tests, so they need to be
63// predictable and human-readable.
64//
65// Note: A lot of this could looks very similar to what's already in the
66// ppaux module. It would be good to refactor things so we only have one
67// parameterizable implementation for printing types.
68
69/// Same as `unique_type_name()` but with the result pushed onto the given
70/// `output` parameter.
71pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
72 t: ty::Ty<'tcx>,
73 output: &mut String) {
74 match t.sty {
75 ty::TyBool => output.push_str("bool"),
76 ty::TyChar => output.push_str("char"),
77 ty::TyStr => output.push_str("str"),
78 ty::TyInt(ast::IntTy::Is) => output.push_str("isize"),
79 ty::TyInt(ast::IntTy::I8) => output.push_str("i8"),
80 ty::TyInt(ast::IntTy::I16) => output.push_str("i16"),
81 ty::TyInt(ast::IntTy::I32) => output.push_str("i32"),
82 ty::TyInt(ast::IntTy::I64) => output.push_str("i64"),
83 ty::TyUint(ast::UintTy::Us) => output.push_str("usize"),
84 ty::TyUint(ast::UintTy::U8) => output.push_str("u8"),
85 ty::TyUint(ast::UintTy::U16) => output.push_str("u16"),
86 ty::TyUint(ast::UintTy::U32) => output.push_str("u32"),
87 ty::TyUint(ast::UintTy::U64) => output.push_str("u64"),
88 ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"),
89 ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"),
90 ty::TyStruct(adt_def, substs) |
91 ty::TyEnum(adt_def, substs) => {
92 push_item_name(tcx, adt_def.did, output);
93 push_type_params(tcx, &substs.types, &[], output);
94 },
95 ty::TyTuple(component_types) => {
96 output.push('(');
97 for &component_type in component_types {
98 push_unique_type_name(tcx, component_type, output);
99 output.push_str(", ");
100 }
101 if !component_types.is_empty() {
102 output.pop();
103 output.pop();
104 }
105 output.push(')');
106 },
107 ty::TyBox(inner_type) => {
108 output.push_str("Box<");
109 push_unique_type_name(tcx, inner_type, output);
110 output.push('>');
111 },
112 ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => {
113 output.push('*');
114 match mutbl {
115 hir::MutImmutable => output.push_str("const "),
116 hir::MutMutable => output.push_str("mut "),
117 }
118
119 push_unique_type_name(tcx, inner_type, output);
120 },
121 ty::TyRef(_, ty::TypeAndMut { ty: inner_type, mutbl }) => {
122 output.push('&');
123 if mutbl == hir::MutMutable {
124 output.push_str("mut ");
125 }
126
127 push_unique_type_name(tcx, inner_type, output);
128 },
129 ty::TyArray(inner_type, len) => {
130 output.push('[');
131 push_unique_type_name(tcx, inner_type, output);
132 output.push_str(&format!("; {}", len));
133 output.push(']');
134 },
135 ty::TySlice(inner_type) => {
136 output.push('[');
137 push_unique_type_name(tcx, inner_type, output);
138 output.push(']');
139 },
140 ty::TyTrait(ref trait_data) => {
141 push_item_name(tcx, trait_data.principal.skip_binder().def_id, output);
142 push_type_params(tcx,
143 &trait_data.principal.skip_binder().substs.types,
144 &trait_data.bounds.projection_bounds,
145 output);
146 },
147 ty::TyFnDef(_, _, &ty::BareFnTy{ unsafety, abi, ref sig } ) |
148 ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {
149 if unsafety == hir::Unsafety::Unsafe {
150 output.push_str("unsafe ");
151 }
152
153 if abi != ::abi::Abi::Rust {
154 output.push_str("extern \"");
155 output.push_str(abi.name());
156 output.push_str("\" ");
157 }
158
159 output.push_str("fn(");
160
161 let sig = tcx.erase_late_bound_regions(sig);
162 if !sig.inputs.is_empty() {
163 for &parameter_type in &sig.inputs {
164 push_unique_type_name(tcx, parameter_type, output);
165 output.push_str(", ");
166 }
167 output.pop();
168 output.pop();
169 }
170
171 if sig.variadic {
172 if !sig.inputs.is_empty() {
173 output.push_str(", ...");
174 } else {
175 output.push_str("...");
176 }
177 }
178
179 output.push(')');
180
181 match sig.output {
182 ty::FnConverging(result_type) if result_type.is_nil() => {}
183 ty::FnConverging(result_type) => {
184 output.push_str(" -> ");
185 push_unique_type_name(tcx, result_type, output);
186 }
187 ty::FnDiverging => {
188 output.push_str(" -> !");
189 }
190 }
191 },
192 ty::TyClosure(def_id, ref closure_substs) => {
193 push_item_name(tcx, def_id, output);
194 output.push_str("{");
195 output.push_str(&format!("{}:{}", def_id.krate, def_id.index.as_usize()));
196 output.push_str("}");
197 push_type_params(tcx, &closure_substs.func_substs.types, &[], output);
198 }
199 ty::TyError |
200 ty::TyInfer(_) |
201 ty::TyProjection(..) |
202 ty::TyParam(_) => {
203 bug!("debuginfo: Trying to create type name for \
204 unexpected type: {:?}", t);
205 }
206 }
207}
208
209fn push_item_name(tcx: TyCtxt,
210 def_id: DefId,
211 output: &mut String) {
212 let def_path = tcx.def_path(def_id);
213
214 // some_crate::
215 output.push_str(&tcx.crate_name(def_path.krate));
216 output.push_str("::");
217
218 // foo::bar::ItemName::
219 for part in tcx.def_path(def_id).data {
220 output.push_str(&format!("{}[{}]::",
221 part.data.as_interned_str(),
222 part.disambiguator));
223 }
224
225 // remove final "::"
226 output.pop();
227 output.pop();
228}
229
230fn push_type_params<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
231 types: &'tcx subst::VecPerParamSpace<Ty<'tcx>>,
232 projections: &[ty::PolyProjectionPredicate<'tcx>],
233 output: &mut String) {
234 if types.is_empty() && projections.is_empty() {
235 return;
236 }
237
238 output.push('<');
239
240 for &type_parameter in types {
241 push_unique_type_name(tcx, type_parameter, output);
242 output.push_str(", ");
243 }
244
245 for projection in projections {
246 let projection = projection.skip_binder();
247 let name = token::get_ident_interner().get(projection.projection_ty.item_name);
248 output.push_str(&name[..]);
249 output.push_str("=");
250 push_unique_type_name(tcx, projection.ty, output);
251 output.push_str(", ");
252 }
253
254 output.pop();
255 output.pop();
256
257 output.push('>');
258}
259
260fn push_instance_as_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
261 instance: Instance<'tcx>,
262 output: &mut String) {
263 push_item_name(tcx, instance.def, output);
264 push_type_params(tcx, &instance.substs.types, &[], output);
265}
266
267pub fn def_id_to_string(tcx: TyCtxt, def_id: DefId) -> String {
268 let mut output = String::new();
269 push_item_name(tcx, def_id, &mut output);
270 output
271}
272
273pub fn type_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
274 ty: ty::Ty<'tcx>)
275 -> String {
276 let mut output = String::new();
277 push_unique_type_name(tcx, ty, &mut output);
278 output
279}
280
281impl<'tcx> TransItem<'tcx> {
282
283 pub fn requests_inline<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
284 match *self {
285 TransItem::Fn(ref instance) => {
286 let attributes = tcx.get_attrs(instance.def);
287 attr::requests_inline(&attributes[..])
288 }
289 TransItem::DropGlue(..) => true,
290 TransItem::Static(..) => false,
291 }
292 }
293
294 pub fn is_from_extern_crate(&self) -> bool {
295 match *self {
296 TransItem::Fn(ref instance) => !instance.def.is_local(),
297 TransItem::DropGlue(..) |
298 TransItem::Static(..) => false,
299 }
300 }
301
302 pub fn is_lazily_instantiated(&self) -> bool {
303 match *self {
304 TransItem::Fn(ref instance) => !instance.substs.types.is_empty(),
305 TransItem::DropGlue(..) => true,
306 TransItem::Static(..) => false,
307 }
308 }
309
310 pub fn explicit_linkage<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<llvm::Linkage> {
311 let def_id = match *self {
312 TransItem::Fn(ref instance) => instance.def,
313 TransItem::Static(node_id) => tcx.map.local_def_id(node_id),
314 TransItem::DropGlue(..) => return None,
315 };
316
317 let attributes = tcx.get_attrs(def_id);
318 if let Some(name) = attr::first_attr_value_str_by_name(&attributes, "linkage") {
319 if let Some(linkage) = llvm_linkage_by_name(&name) {
320 Some(linkage)
321 } else {
322 let span = tcx.map.span_if_local(def_id);
323 if let Some(span) = span {
324 tcx.sess.span_fatal(span, "invalid linkage specified")
325 } else {
326 tcx.sess.fatal(&format!("invalid linkage specified: {}", name))
327 }
328 }
329 } else {
330 None
331 }
332 }
333
334 pub fn to_string<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
335 let hir_map = &tcx.map;
336
337 return match *self {
338 TransItem::DropGlue(dg) => {
339 let mut s = String::with_capacity(32);
340 match dg {
341 DropGlueKind::Ty(_) => s.push_str("drop-glue "),
342 DropGlueKind::TyContents(_) => s.push_str("drop-glue-contents "),
343 };
344 push_unique_type_name(tcx, dg.ty(), &mut s);
345 s
346 }
347 TransItem::Fn(instance) => {
348 to_string_internal(tcx, "fn ", instance)
349 },
350 TransItem::Static(node_id) => {
351 let def_id = hir_map.local_def_id(node_id);
352 let empty_substs = tcx.mk_substs(subst::Substs::empty());
353 let instance = Instance::new(def_id, empty_substs);
354 to_string_internal(tcx, "static ", instance)
355 },
356 };
357
358 fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
359 prefix: &str,
360 instance: Instance<'tcx>)
361 -> String {
362 let mut result = String::with_capacity(32);
363 result.push_str(prefix);
364 push_instance_as_string(tcx, instance, &mut result);
365 result
366 }
367 }
368
369 pub fn to_raw_string(&self) -> String {
370 match *self {
371 TransItem::DropGlue(dg) => {
372 format!("DropGlue({})", dg.ty() as *const _ as usize)
373 }
374 TransItem::Fn(instance) => {
375 format!("Fn({:?}, {})",
376 instance.def,
377 instance.substs as *const _ as usize)
378 }
379 TransItem::Static(id) => {
380 format!("Static({:?})", id)
381 }
382 }
383 }
384}