rustc_codegen_llvm/debuginfo/
mod.rs

1#![doc = include_str!("doc.md")]
2
3use std::cell::{OnceCell, RefCell};
4use std::ops::Range;
5use std::sync::Arc;
6use std::{iter, ptr};
7
8use libc::c_uint;
9use metadata::create_subroutine_type;
10use rustc_abi::Size;
11use rustc_codegen_ssa::debuginfo::type_names;
12use rustc_codegen_ssa::mir::debuginfo::VariableKind::*;
13use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind};
14use rustc_codegen_ssa::traits::*;
15use rustc_data_structures::unord::UnordMap;
16use rustc_hir::def_id::{DefId, DefIdMap};
17use rustc_index::IndexVec;
18use rustc_middle::mir;
19use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
20use rustc_middle::ty::{self, GenericArgsRef, Instance, Ty, TypeVisitableExt};
21use rustc_session::Session;
22use rustc_session::config::{self, DebugInfo};
23use rustc_span::{
24    BytePos, Pos, SourceFile, SourceFileAndLine, SourceFileHash, Span, StableSourceFileId, Symbol,
25};
26use rustc_target::callconv::FnAbi;
27use rustc_target::spec::DebuginfoKind;
28use smallvec::SmallVec;
29use tracing::debug;
30
31use self::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER, file_metadata, type_di_node};
32use self::namespace::mangled_name_of_instance;
33use self::utils::{DIB, create_DIArray, is_node_local_to_unit};
34use crate::builder::Builder;
35use crate::common::{AsCCharPtr, CodegenCx};
36use crate::llvm;
37use crate::llvm::debuginfo::{
38    DIArray, DIBuilderBox, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope,
39    DITemplateTypeParameter, DIType, DIVariable,
40};
41use crate::value::Value;
42
43mod create_scope_map;
44mod dwarf_const;
45mod gdb;
46pub(crate) mod metadata;
47mod namespace;
48mod utils;
49
50use self::create_scope_map::compute_mir_scopes;
51pub(crate) use self::metadata::build_global_var_di_node;
52
53// FIXME(Zalathar): These `DW_TAG_*` constants are fake values that were
54// removed from LLVM in 2015, and are only used by our own `RustWrapper.cpp`
55// to decide which C++ API to call. Instead, we should just have two separate
56// FFI functions and choose the correct one on the Rust side.
57#[allow(non_upper_case_globals)]
58const DW_TAG_auto_variable: c_uint = 0x100;
59#[allow(non_upper_case_globals)]
60const DW_TAG_arg_variable: c_uint = 0x101;
61
62/// A context object for maintaining all state needed by the debuginfo module.
63pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> {
64    llmod: &'ll llvm::Module,
65    builder: DIBuilderBox<'ll>,
66    created_files: RefCell<UnordMap<Option<(StableSourceFileId, SourceFileHash)>, &'ll DIFile>>,
67
68    type_map: metadata::TypeMap<'ll, 'tcx>,
69    adt_stack: RefCell<Vec<(DefId, GenericArgsRef<'tcx>)>>,
70    namespace_map: RefCell<DefIdMap<&'ll DIScope>>,
71    recursion_marker_type: OnceCell<&'ll DIType>,
72}
73
74impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
75    pub(crate) fn new(llmod: &'ll llvm::Module) -> Self {
76        debug!("CodegenUnitDebugContext::new");
77        let builder = DIBuilderBox::new(llmod);
78        // DIBuilder inherits context from the module, so we'd better use the same one
79        CodegenUnitDebugContext {
80            llmod,
81            builder,
82            created_files: Default::default(),
83            type_map: Default::default(),
84            adt_stack: Default::default(),
85            namespace_map: RefCell::new(Default::default()),
86            recursion_marker_type: OnceCell::new(),
87        }
88    }
89
90    pub(crate) fn finalize(&self, sess: &Session) {
91        unsafe { llvm::LLVMDIBuilderFinalize(self.builder.as_ref()) };
92
93        match sess.target.debuginfo_kind {
94            DebuginfoKind::Dwarf | DebuginfoKind::DwarfDsym => {
95                // Debuginfo generation in LLVM by default uses a higher
96                // version of dwarf than macOS currently understands. We can
97                // instruct LLVM to emit an older version of dwarf, however,
98                // for macOS to understand. For more info see #11352
99                // This can be overridden using --llvm-opts -dwarf-version,N.
100                // Android has the same issue (#22398)
101                llvm::add_module_flag_u32(
102                    self.llmod,
103                    // In the case where multiple CGUs with different dwarf version
104                    // values are being merged together, such as with cross-crate
105                    // LTO, then we want to use the highest version of dwarf
106                    // we can. This matches Clang's behavior as well.
107                    llvm::ModuleFlagMergeBehavior::Max,
108                    "Dwarf Version",
109                    sess.dwarf_version(),
110                );
111            }
112            DebuginfoKind::Pdb => {
113                // Indicate that we want CodeView debug information
114                llvm::add_module_flag_u32(
115                    self.llmod,
116                    llvm::ModuleFlagMergeBehavior::Warning,
117                    "CodeView",
118                    1,
119                );
120            }
121        }
122
123        // Prevent bitcode readers from deleting the debug info.
124        llvm::add_module_flag_u32(
125            self.llmod,
126            llvm::ModuleFlagMergeBehavior::Warning,
127            "Debug Info Version",
128            unsafe { llvm::LLVMRustDebugMetadataVersion() },
129        );
130    }
131}
132
133/// Creates any deferred debug metadata nodes
134pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
135    if let Some(dbg_cx) = &cx.dbg_cx {
136        debug!("finalize");
137
138        if gdb::needs_gdb_debug_scripts_section(cx) {
139            // Add a .debug_gdb_scripts section to this compile-unit. This will
140            // cause GDB to try and load the gdb_load_rust_pretty_printers.py file,
141            // which activates the Rust pretty printers for binary this section is
142            // contained in.
143            gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
144        }
145
146        dbg_cx.finalize(cx.sess());
147    }
148}
149
150impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
151    // FIXME(eddyb) find a common convention for all of the debuginfo-related
152    // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
153    fn dbg_var_addr(
154        &mut self,
155        dbg_var: &'ll DIVariable,
156        dbg_loc: &'ll DILocation,
157        variable_alloca: Self::Value,
158        direct_offset: Size,
159        indirect_offsets: &[Size],
160        fragment: Option<Range<Size>>,
161    ) {
162        use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst};
163
164        // Convert the direct and indirect offsets and fragment byte range to address ops.
165        let mut addr_ops = SmallVec::<[u64; 8]>::new();
166
167        if direct_offset.bytes() > 0 {
168            addr_ops.push(DW_OP_plus_uconst);
169            addr_ops.push(direct_offset.bytes() as u64);
170        }
171        for &offset in indirect_offsets {
172            addr_ops.push(DW_OP_deref);
173            if offset.bytes() > 0 {
174                addr_ops.push(DW_OP_plus_uconst);
175                addr_ops.push(offset.bytes() as u64);
176            }
177        }
178        if let Some(fragment) = fragment {
179            // `DW_OP_LLVM_fragment` takes as arguments the fragment's
180            // offset and size, both of them in bits.
181            addr_ops.push(DW_OP_LLVM_fragment);
182            addr_ops.push(fragment.start.bits() as u64);
183            addr_ops.push((fragment.end - fragment.start).bits() as u64);
184        }
185
186        unsafe {
187            // FIXME(eddyb) replace `llvm.dbg.declare` with `llvm.dbg.addr`.
188            llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
189                DIB(self.cx()),
190                variable_alloca,
191                dbg_var,
192                addr_ops.as_ptr(),
193                addr_ops.len() as c_uint,
194                dbg_loc,
195                self.llbb(),
196            );
197        }
198    }
199
200    fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) {
201        unsafe {
202            llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, dbg_loc);
203        }
204    }
205
206    fn clear_dbg_loc(&mut self) {
207        unsafe {
208            llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, ptr::null());
209        }
210    }
211
212    fn get_dbg_loc(&self) -> Option<&'ll DILocation> {
213        unsafe { llvm::LLVMGetCurrentDebugLocation2(self.llbuilder) }
214    }
215
216    fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
217        gdb::insert_reference_to_gdb_debug_scripts_section_global(self)
218    }
219
220    fn set_var_name(&mut self, value: &'ll Value, name: &str) {
221        // Avoid wasting time if LLVM value names aren't even enabled.
222        if self.sess().fewer_names() {
223            return;
224        }
225
226        // Only function parameters and instructions are local to a function,
227        // don't change the name of anything else (e.g. globals).
228        let param_or_inst = unsafe {
229            llvm::LLVMIsAArgument(value).is_some() || llvm::LLVMIsAInstruction(value).is_some()
230        };
231        if !param_or_inst {
232            return;
233        }
234
235        // Avoid replacing the name if it already exists.
236        // While we could combine the names somehow, it'd
237        // get noisy quick, and the usefulness is dubious.
238        if llvm::get_value_name(value).is_empty() {
239            llvm::set_value_name(value, name.as_bytes());
240        }
241    }
242}
243
244/// A source code location used to generate debug information.
245// FIXME(eddyb) rename this to better indicate it's a duplicate of
246// `rustc_span::Loc` rather than `DILocation`, perhaps by making
247// `lookup_char_pos` return the right information instead.
248struct DebugLoc {
249    /// Information about the original source file.
250    file: Arc<SourceFile>,
251    /// The (1-based) line number.
252    line: u32,
253    /// The (1-based) column number.
254    col: u32,
255}
256
257impl<'ll> CodegenCx<'ll, '_> {
258    /// Looks up debug source information about a `BytePos`.
259    // FIXME(eddyb) rename this to better indicate it's a duplicate of
260    // `lookup_char_pos` rather than `dbg_loc`, perhaps by making
261    // `lookup_char_pos` return the right information instead.
262    fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
263        let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
264            Ok(SourceFileAndLine { sf: file, line }) => {
265                let line_pos = file.lines()[line];
266
267                // Use 1-based indexing.
268                let line = (line + 1) as u32;
269                let col = (file.relative_position(pos) - line_pos).to_u32() + 1;
270
271                (file, line, col)
272            }
273            Err(file) => (file, UNKNOWN_LINE_NUMBER, UNKNOWN_COLUMN_NUMBER),
274        };
275
276        // For MSVC, omit the column number.
277        // Otherwise, emit it. This mimics clang behaviour.
278        // See discussion in https://github.com/rust-lang/rust/issues/42921
279        if self.sess().target.is_like_msvc {
280            DebugLoc { file, line, col: UNKNOWN_COLUMN_NUMBER }
281        } else {
282            DebugLoc { file, line, col }
283        }
284    }
285
286    fn create_template_type_parameter(
287        &self,
288        name: &str,
289        actual_type_metadata: &'ll DIType,
290    ) -> &'ll DITemplateTypeParameter {
291        unsafe {
292            llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
293                DIB(self),
294                None,
295                name.as_c_char_ptr(),
296                name.len(),
297                actual_type_metadata,
298            )
299        }
300    }
301}
302
303impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
304    fn create_function_debug_context(
305        &self,
306        instance: Instance<'tcx>,
307        fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
308        llfn: &'ll Value,
309        mir: &mir::Body<'tcx>,
310    ) -> Option<FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>> {
311        if self.sess().opts.debuginfo == DebugInfo::None {
312            return None;
313        }
314
315        // Initialize fn debug context (including scopes).
316        let empty_scope = DebugScope {
317            dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)),
318            inlined_at: None,
319            file_start_pos: BytePos(0),
320            file_end_pos: BytePos(0),
321        };
322        let mut fn_debug_context = FunctionDebugContext {
323            scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes),
324            inlined_function_scopes: Default::default(),
325        };
326
327        // Fill in all the scopes, with the information from the MIR body.
328        compute_mir_scopes(self, instance, mir, &mut fn_debug_context);
329
330        Some(fn_debug_context)
331    }
332
333    fn dbg_scope_fn(
334        &self,
335        instance: Instance<'tcx>,
336        fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
337        maybe_definition_llfn: Option<&'ll Value>,
338    ) -> &'ll DIScope {
339        let tcx = self.tcx;
340
341        let def_id = instance.def_id();
342        let (containing_scope, is_method) = get_containing_scope(self, instance);
343        let span = tcx.def_span(def_id);
344        let loc = self.lookup_debug_loc(span.lo());
345        let file_metadata = file_metadata(self, &loc.file);
346
347        let function_type_metadata =
348            create_subroutine_type(self, get_function_signature(self, fn_abi));
349
350        let mut name = String::with_capacity(64);
351        type_names::push_item_name(tcx, def_id, false, &mut name);
352
353        // Find the enclosing function, in case this is a closure.
354        let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id);
355
356        // We look up the generics of the enclosing function and truncate the args
357        // to their length in order to cut off extra stuff that might be in there for
358        // closures or coroutines.
359        let generics = tcx.generics_of(enclosing_fn_def_id);
360        let args = instance.args.truncate_to(tcx, generics);
361
362        type_names::push_generic_params(
363            tcx,
364            tcx.normalize_erasing_regions(self.typing_env(), args),
365            &mut name,
366        );
367
368        let template_parameters = get_template_parameters(self, generics, args);
369
370        let linkage_name = &mangled_name_of_instance(self, instance).name;
371        // Omit the linkage_name if it is the same as subprogram name.
372        let linkage_name = if &name == linkage_name { "" } else { linkage_name };
373
374        // FIXME(eddyb) does this need to be separate from `loc.line` for some reason?
375        let scope_line = loc.line;
376
377        let mut flags = DIFlags::FlagPrototyped;
378
379        if fn_abi.ret.layout.is_uninhabited() {
380            flags |= DIFlags::FlagNoReturn;
381        }
382
383        let mut spflags = DISPFlags::SPFlagDefinition;
384        if is_node_local_to_unit(self, def_id) {
385            spflags |= DISPFlags::SPFlagLocalToUnit;
386        }
387        if self.sess().opts.optimize != config::OptLevel::No {
388            spflags |= DISPFlags::SPFlagOptimized;
389        }
390        if let Some((id, _)) = tcx.entry_fn(()) {
391            if id == def_id {
392                spflags |= DISPFlags::SPFlagMainSubprogram;
393            }
394        }
395
396        // When we're adding a method to a type DIE, we only want a DW_AT_declaration there, because
397        // LLVM LTO can't unify type definitions when a child DIE is a full subprogram definition.
398        // When we use this `decl` below, the subprogram definition gets created at the CU level
399        // with a DW_AT_specification pointing back to the type's declaration.
400        let decl = is_method.then(|| unsafe {
401            llvm::LLVMRustDIBuilderCreateMethod(
402                DIB(self),
403                containing_scope,
404                name.as_c_char_ptr(),
405                name.len(),
406                linkage_name.as_c_char_ptr(),
407                linkage_name.len(),
408                file_metadata,
409                loc.line,
410                function_type_metadata,
411                flags,
412                spflags & !DISPFlags::SPFlagDefinition,
413                template_parameters,
414            )
415        });
416
417        return unsafe {
418            llvm::LLVMRustDIBuilderCreateFunction(
419                DIB(self),
420                containing_scope,
421                name.as_c_char_ptr(),
422                name.len(),
423                linkage_name.as_c_char_ptr(),
424                linkage_name.len(),
425                file_metadata,
426                loc.line,
427                function_type_metadata,
428                scope_line,
429                flags,
430                spflags,
431                maybe_definition_llfn,
432                template_parameters,
433                decl,
434            )
435        };
436
437        fn get_function_signature<'ll, 'tcx>(
438            cx: &CodegenCx<'ll, 'tcx>,
439            fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
440        ) -> &'ll DIArray {
441            if cx.sess().opts.debuginfo != DebugInfo::Full {
442                return create_DIArray(DIB(cx), &[]);
443            }
444
445            let mut signature = Vec::with_capacity(fn_abi.args.len() + 1);
446
447            // Return type -- llvm::DIBuilder wants this at index 0
448            signature.push(if fn_abi.ret.is_ignore() {
449                None
450            } else {
451                Some(type_di_node(cx, fn_abi.ret.layout.ty))
452            });
453
454            // Arguments types
455            if cx.sess().target.is_like_msvc {
456                // FIXME(#42800):
457                // There is a bug in MSDIA that leads to a crash when it encounters
458                // a fixed-size array of `u8` or something zero-sized in a
459                // function-type (see #40477).
460                // As a workaround, we replace those fixed-size arrays with a
461                // pointer-type. So a function `fn foo(a: u8, b: [u8; 4])` would
462                // appear as `fn foo(a: u8, b: *const u8)` in debuginfo,
463                // and a function `fn bar(x: [(); 7])` as `fn bar(x: *const ())`.
464                // This transformed type is wrong, but these function types are
465                // already inaccurate due to ABI adjustments (see #42800).
466                signature.extend(fn_abi.args.iter().map(|arg| {
467                    let t = arg.layout.ty;
468                    let t = match t.kind() {
469                        ty::Array(ct, _)
470                            if (*ct == cx.tcx.types.u8) || cx.layout_of(*ct).is_zst() =>
471                        {
472                            Ty::new_imm_ptr(cx.tcx, *ct)
473                        }
474                        _ => t,
475                    };
476                    Some(type_di_node(cx, t))
477                }));
478            } else {
479                signature
480                    .extend(fn_abi.args.iter().map(|arg| Some(type_di_node(cx, arg.layout.ty))));
481            }
482
483            create_DIArray(DIB(cx), &signature[..])
484        }
485
486        fn get_template_parameters<'ll, 'tcx>(
487            cx: &CodegenCx<'ll, 'tcx>,
488            generics: &ty::Generics,
489            args: GenericArgsRef<'tcx>,
490        ) -> &'ll DIArray {
491            if args.types().next().is_none() {
492                return create_DIArray(DIB(cx), &[]);
493            }
494
495            // Again, only create type information if full debuginfo is enabled
496            let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full {
497                let names = get_parameter_names(cx, generics);
498                iter::zip(args, names)
499                    .filter_map(|(kind, name)| {
500                        kind.as_type().map(|ty| {
501                            let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
502                            let actual_type_metadata = type_di_node(cx, actual_type);
503                            Some(cx.create_template_type_parameter(
504                                name.as_str(),
505                                actual_type_metadata,
506                            ))
507                        })
508                    })
509                    .collect()
510            } else {
511                vec![]
512            };
513
514            create_DIArray(DIB(cx), &template_params)
515        }
516
517        fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
518            let mut names = generics.parent.map_or_else(Vec::new, |def_id| {
519                get_parameter_names(cx, cx.tcx.generics_of(def_id))
520            });
521            names.extend(generics.own_params.iter().map(|param| param.name));
522            names
523        }
524
525        /// Returns a scope, plus `true` if that's a type scope for "class" methods,
526        /// otherwise `false` for plain namespace scopes.
527        fn get_containing_scope<'ll, 'tcx>(
528            cx: &CodegenCx<'ll, 'tcx>,
529            instance: Instance<'tcx>,
530        ) -> (&'ll DIScope, bool) {
531            // First, let's see if this is a method within an inherent impl. Because
532            // if yes, we want to make the result subroutine DIE a child of the
533            // subroutine's self-type.
534            if let Some(impl_def_id) = cx.tcx.impl_of_method(instance.def_id()) {
535                // If the method does *not* belong to a trait, proceed
536                if cx.tcx.trait_id_of_impl(impl_def_id).is_none() {
537                    let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(
538                        instance.args,
539                        cx.typing_env(),
540                        cx.tcx.type_of(impl_def_id),
541                    );
542
543                    // Only "class" methods are generally understood by LLVM,
544                    // so avoid methods on other types (e.g., `<*mut T>::null`).
545                    if let ty::Adt(def, ..) = impl_self_ty.kind()
546                        && !def.is_box()
547                    {
548                        // Again, only create type information if full debuginfo is enabled
549                        if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param()
550                        {
551                            return (type_di_node(cx, impl_self_ty), true);
552                        } else {
553                            return (namespace::item_namespace(cx, def.did()), false);
554                        }
555                    }
556                } else {
557                    // For trait method impls we still use the "parallel namespace"
558                    // strategy
559                }
560            }
561
562            let scope = namespace::item_namespace(
563                cx,
564                DefId {
565                    krate: instance.def_id().krate,
566                    index: cx
567                        .tcx
568                        .def_key(instance.def_id())
569                        .parent
570                        .expect("get_containing_scope: missing parent?"),
571                },
572            );
573            (scope, false)
574        }
575    }
576
577    fn dbg_loc(
578        &self,
579        scope: &'ll DIScope,
580        inlined_at: Option<&'ll DILocation>,
581        span: Span,
582    ) -> &'ll DILocation {
583        // When emitting debugging information, DWARF (i.e. everything but MSVC)
584        // treats line 0 as a magic value meaning that the code could not be
585        // attributed to any line in the source. That's also exactly what dummy
586        // spans are. Make that equivalence here, rather than passing dummy spans
587        // to lookup_debug_loc, which will return line 1 for them.
588        let (line, col) = if span.is_dummy() && !self.sess().target.is_like_msvc {
589            (0, 0)
590        } else {
591            let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo());
592            (line, col)
593        };
594
595        unsafe { llvm::LLVMDIBuilderCreateDebugLocation(self.llcx, line, col, scope, inlined_at) }
596    }
597
598    fn create_vtable_debuginfo(
599        &self,
600        ty: Ty<'tcx>,
601        trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
602        vtable: Self::Value,
603    ) {
604        metadata::create_vtable_di_node(self, ty, trait_ref, vtable)
605    }
606
607    fn extend_scope_to_file(
608        &self,
609        scope_metadata: &'ll DIScope,
610        file: &rustc_span::SourceFile,
611    ) -> &'ll DILexicalBlock {
612        metadata::extend_scope_to_file(self, scope_metadata, file)
613    }
614
615    fn debuginfo_finalize(&self) {
616        finalize(self)
617    }
618
619    // FIXME(eddyb) find a common convention for all of the debuginfo-related
620    // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
621    fn create_dbg_var(
622        &self,
623        variable_name: Symbol,
624        variable_type: Ty<'tcx>,
625        scope_metadata: &'ll DIScope,
626        variable_kind: VariableKind,
627        span: Span,
628    ) -> &'ll DIVariable {
629        let loc = self.lookup_debug_loc(span.lo());
630        let file_metadata = file_metadata(self, &loc.file);
631
632        let type_metadata = type_di_node(self, variable_type);
633
634        let (argument_index, dwarf_tag) = match variable_kind {
635            ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable),
636            LocalVariable => (0, DW_TAG_auto_variable),
637        };
638        let align = self.align_of(variable_type);
639
640        let name = variable_name.as_str();
641        unsafe {
642            llvm::LLVMRustDIBuilderCreateVariable(
643                DIB(self),
644                dwarf_tag,
645                scope_metadata,
646                name.as_c_char_ptr(),
647                name.len(),
648                file_metadata,
649                loc.line,
650                type_metadata,
651                true,
652                DIFlags::FlagZero,
653                argument_index,
654                align.bits() as u32,
655            )
656        }
657    }
658}