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