]>
Commit | Line | Data |
---|---|---|
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 | ||
17 | use base::llvm_linkage_by_name; | |
18 | use glue::DropGlueKind; | |
19 | use llvm; | |
20 | use monomorphize::Instance; | |
21 | use rustc::hir; | |
22 | use rustc::hir::def_id::DefId; | |
23 | use rustc::ty::{self, Ty, TyCtxt}; | |
24 | use rustc::ty::subst; | |
25 | use std::hash::{Hash, Hasher}; | |
26 | use syntax::ast::{self, NodeId}; | |
27 | use syntax::attr; | |
28 | use syntax::parse::token; | |
29 | ||
30 | #[derive(PartialEq, Eq, Clone, Copy, Debug)] | |
31 | pub enum TransItem<'tcx> { | |
32 | DropGlue(DropGlueKind<'tcx>), | |
33 | Fn(Instance<'tcx>), | |
34 | Static(NodeId) | |
35 | } | |
36 | ||
37 | impl<'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. | |
71 | pub 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 ¶meter_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 | ||
209 | fn 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 | ||
230 | fn 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 | ||
260 | fn 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 | ||
267 | pub 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 | ||
273 | pub 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 | ||
281 | impl<'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 | } |