]> git.proxmox.com Git - rustc.git/blame - src/librustc_trans/trans/debuginfo/mod.rs
Imported Upstream version 1.8.0+dfsg1
[rustc.git] / src / librustc_trans / trans / debuginfo / mod.rs
CommitLineData
d9579d0f
AL
1// Copyright 2012-2015 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// See doc.rs for documentation.
12mod doc;
13
14use self::VariableAccess::*;
15use self::VariableKind::*;
16
17use self::utils::{DIB, span_start, assert_type_for_node_id, contains_nodebug_attribute,
18 create_DIArray, is_node_local_to_unit};
19use self::namespace::{namespace_for_item, NamespaceTreeNode};
20use self::type_names::compute_debuginfo_type_name;
c1a9b12d
SL
21use self::metadata::{type_metadata, diverging_type_metadata};
22use self::metadata::{file_metadata, scope_metadata, TypeMap, compile_unit_metadata};
d9579d0f
AL
23use self::source_loc::InternalDebugLocation;
24
25use llvm;
26use llvm::{ModuleRef, ContextRef, ValueRef};
27use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray,
28 DIDescriptor, FlagPrototyped};
e9174d1e
SL
29use middle::def_id::DefId;
30use middle::infer::normalize_associated_type;
d9579d0f 31use middle::subst::{self, Substs};
e9174d1e
SL
32use rustc_front;
33use rustc_front::hir;
e9174d1e 34
d9579d0f
AL
35use trans::common::{NodeIdAndSpan, CrateContext, FunctionContext, Block};
36use trans;
c1a9b12d 37use trans::{monomorphize, type_of};
92a42be0 38use middle::infer;
c1a9b12d 39use middle::ty::{self, Ty};
d9579d0f 40use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
c1a9b12d 41use util::nodemap::{NodeMap, FnvHashMap, FnvHashSet};
e9174d1e 42use rustc::front::map as hir_map;
d9579d0f
AL
43
44use libc::c_uint;
45use std::cell::{Cell, RefCell};
46use std::ffi::CString;
47use std::ptr;
48use std::rc::Rc;
e9174d1e 49
d9579d0f 50use syntax::codemap::{Span, Pos};
7453a54e
SL
51use syntax::{ast, codemap};
52use syntax::abi::Abi;
b039eaaf 53use syntax::attr::IntType;
d9579d0f
AL
54use syntax::parse::token::{self, special_idents};
55
56pub mod gdb;
57mod utils;
58mod namespace;
59mod type_names;
60mod metadata;
61mod create_scope_map;
62mod source_loc;
63
64pub use self::source_loc::set_source_location;
65pub use self::source_loc::clear_source_location;
66pub use self::source_loc::start_emitting_source_locations;
67pub use self::source_loc::get_cleanup_debug_loc_for_ast_node;
68pub use self::source_loc::with_source_location_override;
69pub use self::metadata::create_match_binding_metadata;
70pub use self::metadata::create_argument_metadata;
71pub use self::metadata::create_captured_var_metadata;
72pub use self::metadata::create_global_var_metadata;
73pub use self::metadata::create_local_var_metadata;
74
75#[allow(non_upper_case_globals)]
76const DW_TAG_auto_variable: c_uint = 0x100;
77#[allow(non_upper_case_globals)]
78const DW_TAG_arg_variable: c_uint = 0x101;
79
80/// A context object for maintaining all state needed by the debuginfo module.
81pub struct CrateDebugContext<'tcx> {
82 llcontext: ContextRef,
83 builder: DIBuilderRef,
84 current_debug_location: Cell<InternalDebugLocation>,
85 created_files: RefCell<FnvHashMap<String, DIFile>>,
e9174d1e 86 created_enum_disr_types: RefCell<FnvHashMap<(DefId, IntType), DIType>>,
d9579d0f
AL
87
88 type_map: RefCell<TypeMap<'tcx>>,
89 namespace_map: RefCell<FnvHashMap<Vec<ast::Name>, Rc<NamespaceTreeNode>>>,
90
91 // This collection is used to assert that composite types (structs, enums,
92 // ...) have their members only set once:
93 composite_types_completed: RefCell<FnvHashSet<DIType>>,
94}
95
96impl<'tcx> CrateDebugContext<'tcx> {
97 pub fn new(llmod: ModuleRef) -> CrateDebugContext<'tcx> {
98 debug!("CrateDebugContext::new");
99 let builder = unsafe { llvm::LLVMDIBuilderCreate(llmod) };
100 // DIBuilder inherits context from the module, so we'd better use the same one
101 let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) };
102 return CrateDebugContext {
103 llcontext: llcontext,
104 builder: builder,
105 current_debug_location: Cell::new(InternalDebugLocation::UnknownLocation),
106 created_files: RefCell::new(FnvHashMap()),
c1a9b12d 107 created_enum_disr_types: RefCell::new(FnvHashMap()),
d9579d0f
AL
108 type_map: RefCell::new(TypeMap::new()),
109 namespace_map: RefCell::new(FnvHashMap()),
110 composite_types_completed: RefCell::new(FnvHashSet()),
111 };
112 }
113}
114
115pub enum FunctionDebugContext {
116 RegularContext(Box<FunctionDebugContextData>),
117 DebugInfoDisabled,
118 FunctionWithoutDebugInfo,
119}
120
121impl FunctionDebugContext {
122 fn get_ref<'a>(&'a self,
123 cx: &CrateContext,
124 span: Span)
125 -> &'a FunctionDebugContextData {
126 match *self {
127 FunctionDebugContext::RegularContext(box ref data) => data,
128 FunctionDebugContext::DebugInfoDisabled => {
129 cx.sess().span_bug(span,
130 FunctionDebugContext::debuginfo_disabled_message());
131 }
132 FunctionDebugContext::FunctionWithoutDebugInfo => {
133 cx.sess().span_bug(span,
134 FunctionDebugContext::should_be_ignored_message());
135 }
136 }
137 }
138
139 fn debuginfo_disabled_message() -> &'static str {
140 "debuginfo: Error trying to access FunctionDebugContext although debug info is disabled!"
141 }
142
143 fn should_be_ignored_message() -> &'static str {
144 "debuginfo: Error trying to access FunctionDebugContext for function that should be \
145 ignored by debug info!"
146 }
147}
148
9cc50fc6 149pub struct FunctionDebugContextData {
d9579d0f
AL
150 scope_map: RefCell<NodeMap<DIScope>>,
151 fn_metadata: DISubprogram,
152 argument_counter: Cell<usize>,
153 source_locations_enabled: Cell<bool>,
154 source_location_override: Cell<bool>,
155}
156
157pub enum VariableAccess<'a> {
158 // The llptr given is an alloca containing the variable's value
159 DirectVariable { alloca: ValueRef },
160 // The llptr given is an alloca containing the start of some pointer chain
161 // leading to the variable's content.
162 IndirectVariable { alloca: ValueRef, address_operations: &'a [i64] }
163}
164
165pub enum VariableKind {
166 ArgumentVariable(usize /*index*/),
167 LocalVariable,
168 CapturedVariable,
169}
170
171/// Create any deferred debug metadata nodes
172pub fn finalize(cx: &CrateContext) {
173 if cx.dbg_cx().is_none() {
174 return;
175 }
176
177 debug!("finalize");
178 let _ = compile_unit_metadata(cx);
179
180 if gdb::needs_gdb_debug_scripts_section(cx) {
181 // Add a .debug_gdb_scripts section to this compile-unit. This will
182 // cause GDB to try and load the gdb_load_rust_pretty_printers.py file,
183 // which activates the Rust pretty printers for binary this section is
184 // contained in.
185 gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
186 }
187
188 unsafe {
189 llvm::LLVMDIBuilderFinalize(DIB(cx));
190 llvm::LLVMDIBuilderDispose(DIB(cx));
191 // Debuginfo generation in LLVM by default uses a higher
192 // version of dwarf than OS X currently understands. We can
193 // instruct LLVM to emit an older version of dwarf, however,
194 // for OS X to understand. For more info see #11352
195 // This can be overridden using --llvm-opts -dwarf-version,N.
196 // Android has the same issue (#22398)
197 if cx.sess().target.target.options.is_like_osx ||
198 cx.sess().target.target.options.is_like_android {
199 llvm::LLVMRustAddModuleFlag(cx.llmod(),
200 "Dwarf Version\0".as_ptr() as *const _,
201 2)
202 }
203
7453a54e
SL
204 // Indicate that we want CodeView debug information on MSVC
205 if cx.sess().target.target.options.is_like_msvc {
206 llvm::LLVMRustAddModuleFlag(cx.llmod(),
207 "CodeView\0".as_ptr() as *const _,
208 1)
209 }
210
d9579d0f
AL
211 // Prevent bitcode readers from deleting the debug info.
212 let ptr = "Debug Info Version\0".as_ptr();
213 llvm::LLVMRustAddModuleFlag(cx.llmod(), ptr as *const _,
62682a34 214 llvm::LLVMRustDebugMetadataVersion());
d9579d0f
AL
215 };
216}
217
218/// Creates the function-specific debug context.
219///
220/// Returns the FunctionDebugContext for the function which holds state needed
221/// for debug info creation. The function may also return another variant of the
222/// FunctionDebugContext enum which indicates why no debuginfo should be created
223/// for the function.
224pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
225 fn_ast_id: ast::NodeId,
226 param_substs: &Substs<'tcx>,
227 llfn: ValueRef) -> FunctionDebugContext {
228 if cx.sess().opts.debuginfo == NoDebugInfo {
229 return FunctionDebugContext::DebugInfoDisabled;
230 }
231
232 // Clear the debug location so we don't assign them in the function prelude.
233 // Do this here already, in case we do an early exit from this function.
234 source_loc::set_debug_location(cx, InternalDebugLocation::UnknownLocation);
235
236 if fn_ast_id == ast::DUMMY_NODE_ID {
237 // This is a function not linked to any source location, so don't
238 // generate debuginfo for it.
239 return FunctionDebugContext::FunctionWithoutDebugInfo;
240 }
241
e9174d1e 242 let empty_generics = rustc_front::util::empty_generics();
d9579d0f
AL
243
244 let fnitem = cx.tcx().map.get(fn_ast_id);
245
246 let (name, fn_decl, generics, top_level_block, span, has_path) = match fnitem {
e9174d1e 247 hir_map::NodeItem(ref item) => {
d9579d0f
AL
248 if contains_nodebug_attribute(&item.attrs) {
249 return FunctionDebugContext::FunctionWithoutDebugInfo;
250 }
251
252 match item.node {
e9174d1e 253 hir::ItemFn(ref fn_decl, _, _, _, ref generics, ref top_level_block) => {
b039eaaf 254 (item.name, fn_decl, generics, top_level_block, item.span, true)
d9579d0f
AL
255 }
256 _ => {
257 cx.sess().span_bug(item.span,
258 "create_function_debug_context: item bound to non-function");
259 }
260 }
261 }
e9174d1e 262 hir_map::NodeImplItem(impl_item) => {
d9579d0f 263 match impl_item.node {
92a42be0 264 hir::ImplItemKind::Method(ref sig, ref body) => {
d9579d0f
AL
265 if contains_nodebug_attribute(&impl_item.attrs) {
266 return FunctionDebugContext::FunctionWithoutDebugInfo;
267 }
268
b039eaaf 269 (impl_item.name,
d9579d0f
AL
270 &sig.decl,
271 &sig.generics,
272 body,
273 impl_item.span,
274 true)
275 }
276 _ => {
277 cx.sess().span_bug(impl_item.span,
278 "create_function_debug_context() \
279 called on non-method impl item?!")
280 }
281 }
282 }
e9174d1e 283 hir_map::NodeExpr(ref expr) => {
d9579d0f 284 match expr.node {
e9174d1e 285 hir::ExprClosure(_, ref fn_decl, ref top_level_block) => {
d9579d0f
AL
286 let name = format!("fn{}", token::gensym("fn"));
287 let name = token::intern(&name[..]);
288 (name, fn_decl,
289 // This is not quite right. It should actually inherit
290 // the generics of the enclosing function.
291 &empty_generics,
292 top_level_block,
293 expr.span,
294 // Don't try to lookup the item path:
295 false)
296 }
297 _ => cx.sess().span_bug(expr.span,
298 "create_function_debug_context: expected an expr_fn_block here")
299 }
300 }
e9174d1e 301 hir_map::NodeTraitItem(trait_item) => {
d9579d0f 302 match trait_item.node {
e9174d1e 303 hir::MethodTraitItem(ref sig, Some(ref body)) => {
d9579d0f
AL
304 if contains_nodebug_attribute(&trait_item.attrs) {
305 return FunctionDebugContext::FunctionWithoutDebugInfo;
306 }
307
b039eaaf 308 (trait_item.name,
d9579d0f
AL
309 &sig.decl,
310 &sig.generics,
311 body,
312 trait_item.span,
313 true)
314 }
315 _ => {
316 cx.sess()
317 .bug(&format!("create_function_debug_context: \
318 unexpected sort of node: {:?}",
319 fnitem))
320 }
321 }
322 }
e9174d1e
SL
323 hir_map::NodeForeignItem(..) |
324 hir_map::NodeVariant(..) |
325 hir_map::NodeStructCtor(..) => {
d9579d0f
AL
326 return FunctionDebugContext::FunctionWithoutDebugInfo;
327 }
328 _ => cx.sess().bug(&format!("create_function_debug_context: \
329 unexpected sort of node: {:?}",
330 fnitem))
331 };
332
333 // This can be the case for functions inlined from another crate
334 if span == codemap::DUMMY_SP {
335 return FunctionDebugContext::FunctionWithoutDebugInfo;
336 }
337
338 let loc = span_start(cx, span);
339 let file_metadata = file_metadata(cx, &loc.file.name);
340
341 let function_type_metadata = unsafe {
342 let fn_signature = get_function_signature(cx,
343 fn_ast_id,
d9579d0f
AL
344 param_substs,
345 span);
346 llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature)
347 };
348
349 // Get_template_parameters() will append a `<...>` clause to the function
350 // name if necessary.
c1a9b12d 351 let mut function_name = name.to_string();
d9579d0f
AL
352 let template_parameters = get_template_parameters(cx,
353 generics,
354 param_substs,
355 file_metadata,
356 &mut function_name);
357
e9174d1e 358 // There is no hir_map::Path for hir::ExprClosure-type functions. For now,
d9579d0f 359 // just don't put them into a namespace. In the future this could be improved
e9174d1e 360 // somehow (storing a path in the hir_map, or construct a path using the
d9579d0f
AL
361 // enclosing function).
362 let (linkage_name, containing_scope) = if has_path {
b039eaaf
SL
363 let fn_ast_def_id = cx.tcx().map.local_def_id(fn_ast_id);
364 let namespace_node = namespace_for_item(cx, fn_ast_def_id);
d9579d0f
AL
365 let linkage_name = namespace_node.mangled_name_of_contained_item(
366 &function_name[..]);
367 let containing_scope = namespace_node.scope;
368 (linkage_name, containing_scope)
369 } else {
370 (function_name.clone(), file_metadata)
371 };
372
373 // Clang sets this parameter to the opening brace of the function's block,
374 // so let's do this too.
375 let scope_line = span_start(cx, top_level_block.span).line;
376
377 let is_local_to_unit = is_node_local_to_unit(cx, fn_ast_id);
378
379 let function_name = CString::new(function_name).unwrap();
380 let linkage_name = CString::new(linkage_name).unwrap();
381 let fn_metadata = unsafe {
382 llvm::LLVMDIBuilderCreateFunction(
383 DIB(cx),
384 containing_scope,
385 function_name.as_ptr(),
386 linkage_name.as_ptr(),
387 file_metadata,
388 loc.line as c_uint,
389 function_type_metadata,
390 is_local_to_unit,
391 true,
392 scope_line as c_uint,
393 FlagPrototyped as c_uint,
9cc50fc6 394 cx.sess().opts.optimize != config::OptLevel::No,
d9579d0f
AL
395 llfn,
396 template_parameters,
397 ptr::null_mut())
398 };
399
400 let scope_map = create_scope_map::create_scope_map(cx,
401 &fn_decl.inputs,
7453a54e 402 &top_level_block,
d9579d0f
AL
403 fn_metadata,
404 fn_ast_id);
405
406 // Initialize fn debug context (including scope map and namespace map)
407 let fn_debug_context = box FunctionDebugContextData {
408 scope_map: RefCell::new(scope_map),
409 fn_metadata: fn_metadata,
410 argument_counter: Cell::new(1),
411 source_locations_enabled: Cell::new(false),
412 source_location_override: Cell::new(false),
413 };
414
415
416
417 return FunctionDebugContext::RegularContext(fn_debug_context);
418
419 fn get_function_signature<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
420 fn_ast_id: ast::NodeId,
d9579d0f
AL
421 param_substs: &Substs<'tcx>,
422 error_reporting_span: Span) -> DIArray {
423 if cx.sess().opts.debuginfo == LimitedDebugInfo {
424 return create_DIArray(DIB(cx), &[]);
425 }
426
d9579d0f
AL
427 // Return type -- llvm::DIBuilder wants this at index 0
428 assert_type_for_node_id(cx, fn_ast_id, error_reporting_span);
c1a9b12d 429 let fn_type = cx.tcx().node_id_to_type(fn_ast_id);
92a42be0 430 let fn_type = monomorphize::apply_param_substs(cx.tcx(), param_substs, &fn_type);
c1a9b12d
SL
431
432 let (sig, abi) = match fn_type.sty {
433 ty::TyBareFn(_, ref barefnty) => {
92a42be0
SL
434 let sig = cx.tcx().erase_late_bound_regions(&barefnty.sig);
435 let sig = infer::normalize_associated_type(cx.tcx(), &sig);
436 (sig, barefnty.abi)
c1a9b12d
SL
437 }
438 ty::TyClosure(def_id, ref substs) => {
439 let closure_type = cx.tcx().closure_type(def_id, substs);
92a42be0
SL
440 let sig = cx.tcx().erase_late_bound_regions(&closure_type.sig);
441 let sig = infer::normalize_associated_type(cx.tcx(), &sig);
442 (sig, closure_type.abi)
c1a9b12d
SL
443 }
444
445 _ => cx.sess().bug("get_function_metdata: Expected a function type!")
446 };
c1a9b12d
SL
447
448 let mut signature = Vec::with_capacity(sig.inputs.len() + 1);
449
450 // Return type -- llvm::DIBuilder wants this at index 0
451 signature.push(match sig.output {
452 ty::FnConverging(ret_ty) => match ret_ty.sty {
453 ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
454 _ => type_metadata(cx, ret_ty, codemap::DUMMY_SP)
455 },
456 ty::FnDiverging => diverging_type_metadata(cx)
457 });
458
7453a54e 459 let inputs = &if abi == Abi::RustCall {
c1a9b12d 460 type_of::untuple_arguments(cx, &sig.inputs)
d9579d0f 461 } else {
c1a9b12d
SL
462 sig.inputs
463 };
d9579d0f
AL
464
465 // Arguments types
c1a9b12d
SL
466 for &argument_type in inputs {
467 signature.push(type_metadata(cx, argument_type, codemap::DUMMY_SP));
d9579d0f
AL
468 }
469
470 return create_DIArray(DIB(cx), &signature[..]);
471 }
472
473 fn get_template_parameters<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
e9174d1e 474 generics: &hir::Generics,
d9579d0f
AL
475 param_substs: &Substs<'tcx>,
476 file_metadata: DIFile,
477 name_to_append_suffix_to: &mut String)
478 -> DIArray
479 {
480 let self_type = param_substs.self_ty();
e9174d1e 481 let self_type = normalize_associated_type(cx.tcx(), &self_type);
d9579d0f
AL
482
483 // Only true for static default methods:
484 let has_self_type = self_type.is_some();
485
486 if !generics.is_type_parameterized() && !has_self_type {
487 return create_DIArray(DIB(cx), &[]);
488 }
489
490 name_to_append_suffix_to.push('<');
491
492 // The list to be filled with template parameters:
493 let mut template_params: Vec<DIDescriptor> =
494 Vec::with_capacity(generics.ty_params.len() + 1);
495
496 // Handle self type
497 if has_self_type {
498 let actual_self_type = self_type.unwrap();
499 // Add self type name to <...> clause of function name
500 let actual_self_type_name = compute_debuginfo_type_name(
501 cx,
502 actual_self_type,
503 true);
504
505 name_to_append_suffix_to.push_str(&actual_self_type_name[..]);
506
507 if generics.is_type_parameterized() {
508 name_to_append_suffix_to.push_str(",");
509 }
510
511 // Only create type information if full debuginfo is enabled
512 if cx.sess().opts.debuginfo == FullDebugInfo {
513 let actual_self_type_metadata = type_metadata(cx,
514 actual_self_type,
515 codemap::DUMMY_SP);
516
c1a9b12d 517 let name = special_idents::type_self.name.as_str();
d9579d0f
AL
518
519 let name = CString::new(name.as_bytes()).unwrap();
520 let param_metadata = unsafe {
521 llvm::LLVMDIBuilderCreateTemplateTypeParameter(
522 DIB(cx),
62682a34 523 ptr::null_mut(),
d9579d0f
AL
524 name.as_ptr(),
525 actual_self_type_metadata,
62682a34 526 file_metadata,
d9579d0f
AL
527 0,
528 0)
529 };
530
531 template_params.push(param_metadata);
532 }
533 }
534
535 // Handle other generic parameters
536 let actual_types = param_substs.types.get_slice(subst::FnSpace);
b039eaaf 537 for (index, &hir::TyParam{ name, .. }) in generics.ty_params.iter().enumerate() {
d9579d0f
AL
538 let actual_type = actual_types[index];
539 // Add actual type name to <...> clause of function name
540 let actual_type_name = compute_debuginfo_type_name(cx,
541 actual_type,
542 true);
543 name_to_append_suffix_to.push_str(&actual_type_name[..]);
544
545 if index != generics.ty_params.len() - 1 {
546 name_to_append_suffix_to.push_str(",");
547 }
548
549 // Again, only create type information if full debuginfo is enabled
550 if cx.sess().opts.debuginfo == FullDebugInfo {
551 let actual_type_metadata = type_metadata(cx, actual_type, codemap::DUMMY_SP);
b039eaaf 552 let name = CString::new(name.as_str().as_bytes()).unwrap();
d9579d0f
AL
553 let param_metadata = unsafe {
554 llvm::LLVMDIBuilderCreateTemplateTypeParameter(
555 DIB(cx),
62682a34 556 ptr::null_mut(),
d9579d0f
AL
557 name.as_ptr(),
558 actual_type_metadata,
62682a34 559 file_metadata,
d9579d0f
AL
560 0,
561 0)
562 };
563 template_params.push(param_metadata);
564 }
565 }
566
567 name_to_append_suffix_to.push('>');
568
569 return create_DIArray(DIB(cx), &template_params[..]);
570 }
571}
572
573fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
574 variable_name: ast::Name,
575 variable_type: Ty<'tcx>,
576 scope_metadata: DIScope,
577 variable_access: VariableAccess,
578 variable_kind: VariableKind,
579 span: Span) {
580 let cx: &CrateContext = bcx.ccx();
581
582 let filename = span_start(cx, span).file.name.clone();
583 let file_metadata = file_metadata(cx, &filename[..]);
584
d9579d0f
AL
585 let loc = span_start(cx, span);
586 let type_metadata = type_metadata(cx, variable_type, span);
587
588 let (argument_index, dwarf_tag) = match variable_kind {
589 ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable),
590 LocalVariable |
591 CapturedVariable => (0, DW_TAG_auto_variable)
592 };
593
c1a9b12d 594 let name = CString::new(variable_name.as_str().as_bytes()).unwrap();
d9579d0f
AL
595 match (variable_access, &[][..]) {
596 (DirectVariable { alloca }, address_operations) |
597 (IndirectVariable {alloca, address_operations}, _) => {
598 let metadata = unsafe {
599 llvm::LLVMDIBuilderCreateVariable(
600 DIB(cx),
601 dwarf_tag,
602 scope_metadata,
603 name.as_ptr(),
604 file_metadata,
605 loc.line as c_uint,
606 type_metadata,
9cc50fc6 607 cx.sess().opts.optimize != config::OptLevel::No,
d9579d0f
AL
608 0,
609 address_operations.as_ptr(),
610 address_operations.len() as c_uint,
611 argument_index)
612 };
613 source_loc::set_debug_location(cx, InternalDebugLocation::new(scope_metadata,
614 loc.line,
615 loc.col.to_usize()));
616 unsafe {
62682a34 617 let debug_loc = llvm::LLVMGetCurrentDebugLocation(cx.raw_builder());
d9579d0f
AL
618 let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(
619 DIB(cx),
620 alloca,
621 metadata,
622 address_operations.as_ptr(),
623 address_operations.len() as c_uint,
62682a34 624 debug_loc,
d9579d0f
AL
625 bcx.llbb);
626
627 llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
628 }
629 }
630 }
631
632 match variable_kind {
633 ArgumentVariable(_) | CapturedVariable => {
634 assert!(!bcx.fcx
635 .debug_context
636 .get_ref(cx, span)
637 .source_locations_enabled
638 .get());
639 source_loc::set_debug_location(cx, InternalDebugLocation::UnknownLocation);
640 }
641 _ => { /* nothing to do */ }
642 }
643}
644
645#[derive(Copy, Clone, PartialEq, Eq, Debug)]
646pub enum DebugLoc {
647 At(ast::NodeId, Span),
648 None
649}
650
651impl DebugLoc {
652 pub fn apply(&self, fcx: &FunctionContext) {
653 match *self {
654 DebugLoc::At(node_id, span) => {
655 source_loc::set_source_location(fcx, node_id, span);
656 }
657 DebugLoc::None => {
658 source_loc::clear_source_location(fcx);
659 }
660 }
661 }
662}
663
664pub trait ToDebugLoc {
665 fn debug_loc(&self) -> DebugLoc;
666}
667
e9174d1e 668impl ToDebugLoc for hir::Expr {
d9579d0f
AL
669 fn debug_loc(&self) -> DebugLoc {
670 DebugLoc::At(self.id, self.span)
671 }
672}
673
674impl ToDebugLoc for NodeIdAndSpan {
675 fn debug_loc(&self) -> DebugLoc {
676 DebugLoc::At(self.id, self.span)
677 }
678}
679
680impl ToDebugLoc for Option<NodeIdAndSpan> {
681 fn debug_loc(&self) -> DebugLoc {
682 match *self {
683 Some(NodeIdAndSpan { id, span }) => DebugLoc::At(id, span),
684 None => DebugLoc::None
685 }
686 }
687}