]> git.lizzy.rs Git - rust.git/blob - src/librustc_codegen_llvm/debuginfo/type_names.rs
Ensure `record_layout_for_printing()` is inlined.
[rust.git] / src / librustc_codegen_llvm / debuginfo / type_names.rs
1 // Type Names for Debug Info.
2
3 use crate::common::CodegenCx;
4 use rustc::hir::def_id::DefId;
5 use rustc::ty::subst::Substs;
6 use rustc::ty::{self, Ty};
7 use rustc_codegen_ssa::traits::*;
8
9 use rustc::hir;
10
11 // Compute the name of the type as it should be stored in debuginfo. Does not do
12 // any caching, i.e., calling the function twice with the same type will also do
13 // the work twice. The `qualified` parameter only affects the first level of the
14 // type name, further levels (i.e., type parameters) are always fully qualified.
15 pub fn compute_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
16                                              t: Ty<'tcx>,
17                                              qualified: bool)
18                                              -> String {
19     let mut result = String::with_capacity(64);
20     push_debuginfo_type_name(cx, t, qualified, &mut result);
21     result
22 }
23
24 // Pushes the name of the type as it should be stored in debuginfo on the
25 // `output` String. See also compute_debuginfo_type_name().
26 pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
27                                           t: Ty<'tcx>,
28                                           qualified: bool,
29                                           output: &mut String) {
30     // When targeting MSVC, emit C++ style type names for compatibility with
31     // .natvis visualizers (and perhaps other existing native debuggers?)
32     let cpp_like_names = cx.sess().target.target.options.is_like_msvc;
33
34     match t.sty {
35         ty::Bool => output.push_str("bool"),
36         ty::Char => output.push_str("char"),
37         ty::Str => output.push_str("str"),
38         ty::Never => output.push_str("!"),
39         ty::Int(int_ty) => output.push_str(int_ty.ty_to_string()),
40         ty::Uint(uint_ty) => output.push_str(uint_ty.ty_to_string()),
41         ty::Float(float_ty) => output.push_str(float_ty.ty_to_string()),
42         ty::Foreign(def_id) => push_item_name(cx, def_id, qualified, output),
43         ty::Adt(def, substs) => {
44             push_item_name(cx, def.did, qualified, output);
45             push_type_params(cx, substs, output);
46         },
47         ty::Tuple(component_types) => {
48             output.push('(');
49             for &component_type in component_types {
50                 push_debuginfo_type_name(cx, component_type, true, output);
51                 output.push_str(", ");
52             }
53             if !component_types.is_empty() {
54                 output.pop();
55                 output.pop();
56             }
57             output.push(')');
58         },
59         ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => {
60             if !cpp_like_names {
61                 output.push('*');
62             }
63             match mutbl {
64                 hir::MutImmutable => output.push_str("const "),
65                 hir::MutMutable => output.push_str("mut "),
66             }
67
68             push_debuginfo_type_name(cx, inner_type, true, output);
69
70             if cpp_like_names {
71                 output.push('*');
72             }
73         },
74         ty::Ref(_, inner_type, mutbl) => {
75             if !cpp_like_names {
76                 output.push('&');
77             }
78             if mutbl == hir::MutMutable {
79                 output.push_str("mut ");
80             }
81
82             push_debuginfo_type_name(cx, inner_type, true, output);
83
84             if cpp_like_names {
85                 output.push('*');
86             }
87         },
88         ty::Array(inner_type, len) => {
89             output.push('[');
90             push_debuginfo_type_name(cx, inner_type, true, output);
91             output.push_str(&format!("; {}", len.unwrap_usize(cx.tcx)));
92             output.push(']');
93         },
94         ty::Slice(inner_type) => {
95             if cpp_like_names {
96                 output.push_str("slice<");
97             } else {
98                 output.push('[');
99             }
100
101             push_debuginfo_type_name(cx, inner_type, true, output);
102
103             if cpp_like_names {
104                 output.push('>');
105             } else {
106                 output.push(']');
107             }
108         },
109         ty::Dynamic(ref trait_data, ..) => {
110             if let Some(principal) = trait_data.principal() {
111                 let principal = cx.tcx.normalize_erasing_late_bound_regions(
112                     ty::ParamEnv::reveal_all(),
113                     &principal,
114                 );
115                 push_item_name(cx, principal.def_id, false, output);
116                 push_type_params(cx, principal.substs, output);
117             } else {
118                 output.push_str("dyn '_");
119             }
120         },
121         ty::FnDef(..) | ty::FnPtr(_) => {
122             let sig = t.fn_sig(cx.tcx);
123             if sig.unsafety() == hir::Unsafety::Unsafe {
124                 output.push_str("unsafe ");
125             }
126
127             let abi = sig.abi();
128             if abi != crate::abi::Abi::Rust {
129                 output.push_str("extern \"");
130                 output.push_str(abi.name());
131                 output.push_str("\" ");
132             }
133
134             output.push_str("fn(");
135
136             let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
137             if !sig.inputs().is_empty() {
138                 for &parameter_type in sig.inputs() {
139                     push_debuginfo_type_name(cx, parameter_type, true, output);
140                     output.push_str(", ");
141                 }
142                 output.pop();
143                 output.pop();
144             }
145
146             if sig.variadic {
147                 if !sig.inputs().is_empty() {
148                     output.push_str(", ...");
149                 } else {
150                     output.push_str("...");
151                 }
152             }
153
154             output.push(')');
155
156             if !sig.output().is_unit() {
157                 output.push_str(" -> ");
158                 push_debuginfo_type_name(cx, sig.output(), true, output);
159             }
160         },
161         ty::Closure(..) => {
162             output.push_str("closure");
163         }
164         ty::Generator(..) => {
165             output.push_str("generator");
166         }
167         ty::Error |
168         ty::Infer(_) |
169         ty::Placeholder(..) |
170         ty::UnnormalizedProjection(..) |
171         ty::Projection(..) |
172         ty::Bound(..) |
173         ty::Opaque(..) |
174         ty::GeneratorWitness(..) |
175         ty::Param(_) => {
176             bug!("debuginfo: Trying to create type name for \
177                   unexpected type: {:?}", t);
178         }
179     }
180
181     fn push_item_name(cx: &CodegenCx<'_, '_>,
182                       def_id: DefId,
183                       qualified: bool,
184                       output: &mut String) {
185         if qualified {
186             output.push_str(&cx.tcx.crate_name(def_id.krate).as_str());
187             for path_element in cx.tcx.def_path(def_id).data {
188                 output.push_str("::");
189                 output.push_str(&path_element.data.as_interned_str().as_str());
190             }
191         } else {
192             output.push_str(&cx.tcx.item_name(def_id).as_str());
193         }
194     }
195
196     // Pushes the type parameters in the given `Substs` to the output string.
197     // This ignores region parameters, since they can't reliably be
198     // reconstructed for items from non-local crates. For local crates, this
199     // would be possible but with inlining and LTO we have to use the least
200     // common denominator - otherwise we would run into conflicts.
201     fn push_type_params<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
202                                   substs: &Substs<'tcx>,
203                                   output: &mut String) {
204         if substs.types().next().is_none() {
205             return;
206         }
207
208         output.push('<');
209
210         for type_parameter in substs.types() {
211             push_debuginfo_type_name(cx, type_parameter, true, output);
212             output.push_str(", ");
213         }
214
215         output.pop();
216         output.pop();
217
218         output.push('>');
219     }
220 }