Importing rustc-1.48.0
Bug: 173721343
Change-Id: Ie8184d9a685086ca8a77266d6c608843f40dc9e1
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
new file mode 100644
index 0000000..7f47b61
--- /dev/null
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
@@ -0,0 +1,95 @@
+use super::metadata::{file_metadata, UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER};
+use super::utils::DIB;
+use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext};
+use rustc_codegen_ssa::traits::*;
+
+use crate::common::CodegenCx;
+use crate::llvm;
+use crate::llvm::debuginfo::{DIScope, DISubprogram};
+use rustc_middle::mir::{Body, SourceScope};
+use rustc_session::config::DebugInfo;
+
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::Idx;
+
+/// Produces DIScope DIEs for each MIR Scope which has variables defined in it.
+pub fn compute_mir_scopes(
+ cx: &CodegenCx<'ll, '_>,
+ mir: &Body<'_>,
+ fn_metadata: &'ll DISubprogram,
+ debug_context: &mut FunctionDebugContext<&'ll DIScope>,
+) {
+ // Find all the scopes with variables defined in them.
+ let mut has_variables = BitSet::new_empty(mir.source_scopes.len());
+
+ // Only consider variables when they're going to be emitted.
+ // FIXME(eddyb) don't even allocate `has_variables` otherwise.
+ if cx.sess().opts.debuginfo == DebugInfo::Full {
+ // FIXME(eddyb) take into account that arguments always have debuginfo,
+ // irrespective of their name (assuming full debuginfo is enabled).
+ // NOTE(eddyb) actually, on second thought, those are always in the
+ // function scope, which always exists.
+ for var_debug_info in &mir.var_debug_info {
+ has_variables.insert(var_debug_info.source_info.scope);
+ }
+ }
+
+ // Instantiate all scopes.
+ for idx in 0..mir.source_scopes.len() {
+ let scope = SourceScope::new(idx);
+ make_mir_scope(cx, &mir, fn_metadata, &has_variables, debug_context, scope);
+ }
+}
+
+fn make_mir_scope(
+ cx: &CodegenCx<'ll, '_>,
+ mir: &Body<'_>,
+ fn_metadata: &'ll DISubprogram,
+ has_variables: &BitSet<SourceScope>,
+ debug_context: &mut FunctionDebugContext<&'ll DISubprogram>,
+ scope: SourceScope,
+) {
+ if debug_context.scopes[scope].is_valid() {
+ return;
+ }
+
+ let scope_data = &mir.source_scopes[scope];
+ let parent_scope = if let Some(parent) = scope_data.parent_scope {
+ make_mir_scope(cx, mir, fn_metadata, has_variables, debug_context, parent);
+ debug_context.scopes[parent]
+ } else {
+ // The root is the function itself.
+ let loc = cx.lookup_debug_loc(mir.span.lo());
+ debug_context.scopes[scope] = DebugScope {
+ scope_metadata: Some(fn_metadata),
+ file_start_pos: loc.file.start_pos,
+ file_end_pos: loc.file.end_pos,
+ };
+ return;
+ };
+
+ if !has_variables.contains(scope) {
+ // Do not create a DIScope if there are no variables
+ // defined in this MIR Scope, to avoid debuginfo bloat.
+ debug_context.scopes[scope] = parent_scope;
+ return;
+ }
+
+ let loc = cx.lookup_debug_loc(scope_data.span.lo());
+ let file_metadata = file_metadata(cx, &loc.file, debug_context.defining_crate);
+
+ let scope_metadata = unsafe {
+ Some(llvm::LLVMRustDIBuilderCreateLexicalBlock(
+ DIB(cx),
+ parent_scope.scope_metadata.unwrap(),
+ file_metadata,
+ loc.line.unwrap_or(UNKNOWN_LINE_NUMBER),
+ loc.col.unwrap_or(UNKNOWN_COLUMN_NUMBER),
+ ))
+ };
+ debug_context.scopes[scope] = DebugScope {
+ scope_metadata,
+ file_start_pos: loc.file.start_pos,
+ file_end_pos: loc.file.end_pos,
+ };
+}
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/doc.rs b/compiler/rustc_codegen_llvm/src/debuginfo/doc.rs
new file mode 100644
index 0000000..b3a8fa2
--- /dev/null
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/doc.rs
@@ -0,0 +1,179 @@
+//! # Debug Info Module
+//!
+//! This module serves the purpose of generating debug symbols. We use LLVM's
+//! [source level debugging](https://llvm.org/docs/SourceLevelDebugging.html)
+//! features for generating the debug information. The general principle is
+//! this:
+//!
+//! Given the right metadata in the LLVM IR, the LLVM code generator is able to
+//! create DWARF debug symbols for the given code. The
+//! [metadata](https://llvm.org/docs/LangRef.html#metadata-type) is structured
+//! much like DWARF *debugging information entries* (DIE), representing type
+//! information such as datatype layout, function signatures, block layout,
+//! variable location and scope information, etc. It is the purpose of this
+//! module to generate correct metadata and insert it into the LLVM IR.
+//!
+//! As the exact format of metadata trees may change between different LLVM
+//! versions, we now use LLVM
+//! [DIBuilder](https://llvm.org/docs/doxygen/html/classllvm_1_1DIBuilder.html)
+//! to create metadata where possible. This will hopefully ease the adaption of
+//! this module to future LLVM versions.
+//!
+//! The public API of the module is a set of functions that will insert the
+//! correct metadata into the LLVM IR when called with the right parameters.
+//! The module is thus driven from an outside client with functions like
+//! `debuginfo::create_local_var_metadata(bx: block, local: &ast::local)`.
+//!
+//! Internally the module will try to reuse already created metadata by
+//! utilizing a cache. The way to get a shared metadata node when needed is
+//! thus to just call the corresponding function in this module:
+//!
+//! let file_metadata = file_metadata(crate_context, path);
+//!
+//! The function will take care of probing the cache for an existing node for
+//! that exact file path.
+//!
+//! All private state used by the module is stored within either the
+//! CrateDebugContext struct (owned by the CodegenCx) or the
+//! FunctionDebugContext (owned by the FunctionCx).
+//!
+//! This file consists of three conceptual sections:
+//! 1. The public interface of the module
+//! 2. Module-internal metadata creation functions
+//! 3. Minor utility functions
+//!
+//!
+//! ## Recursive Types
+//!
+//! Some kinds of types, such as structs and enums can be recursive. That means
+//! that the type definition of some type X refers to some other type which in
+//! turn (transitively) refers to X. This introduces cycles into the type
+//! referral graph. A naive algorithm doing an on-demand, depth-first traversal
+//! of this graph when describing types, can get trapped in an endless loop
+//! when it reaches such a cycle.
+//!
+//! For example, the following simple type for a singly-linked list...
+//!
+//! ```
+//! struct List {
+//! value: i32,
+//! tail: Option<Box<List>>,
+//! }
+//! ```
+//!
+//! will generate the following callstack with a naive DFS algorithm:
+//!
+//! ```
+//! describe(t = List)
+//! describe(t = i32)
+//! describe(t = Option<Box<List>>)
+//! describe(t = Box<List>)
+//! describe(t = List) // at the beginning again...
+//! ...
+//! ```
+//!
+//! To break cycles like these, we use "forward declarations". That is, when
+//! the algorithm encounters a possibly recursive type (any struct or enum), it
+//! immediately creates a type description node and inserts it into the cache
+//! *before* describing the members of the type. This type description is just
+//! a stub (as type members are not described and added to it yet) but it
+//! allows the algorithm to already refer to the type. After the stub is
+//! inserted into the cache, the algorithm continues as before. If it now
+//! encounters a recursive reference, it will hit the cache and does not try to
+//! describe the type anew.
+//!
+//! This behavior is encapsulated in the 'RecursiveTypeDescription' enum,
+//! which represents a kind of continuation, storing all state needed to
+//! continue traversal at the type members after the type has been registered
+//! with the cache. (This implementation approach might be a tad over-
+//! engineered and may change in the future)
+//!
+//!
+//! ## Source Locations and Line Information
+//!
+//! In addition to data type descriptions the debugging information must also
+//! allow to map machine code locations back to source code locations in order
+//! to be useful. This functionality is also handled in this module. The
+//! following functions allow to control source mappings:
+//!
+//! + set_source_location()
+//! + clear_source_location()
+//! + start_emitting_source_locations()
+//!
+//! `set_source_location()` allows to set the current source location. All IR
+//! instructions created after a call to this function will be linked to the
+//! given source location, until another location is specified with
+//! `set_source_location()` or the source location is cleared with
+//! `clear_source_location()`. In the later case, subsequent IR instruction
+//! will not be linked to any source location. As you can see, this is a
+//! stateful API (mimicking the one in LLVM), so be careful with source
+//! locations set by previous calls. It's probably best to not rely on any
+//! specific state being present at a given point in code.
+//!
+//! One topic that deserves some extra attention is *function prologues*. At
+//! the beginning of a function's machine code there are typically a few
+//! instructions for loading argument values into allocas and checking if
+//! there's enough stack space for the function to execute. This *prologue* is
+//! not visible in the source code and LLVM puts a special PROLOGUE END marker
+//! into the line table at the first non-prologue instruction of the function.
+//! In order to find out where the prologue ends, LLVM looks for the first
+//! instruction in the function body that is linked to a source location. So,
+//! when generating prologue instructions we have to make sure that we don't
+//! emit source location information until the 'real' function body begins. For
+//! this reason, source location emission is disabled by default for any new
+//! function being codegened and is only activated after a call to the third
+//! function from the list above, `start_emitting_source_locations()`. This
+//! function should be called right before regularly starting to codegen the
+//! top-level block of the given function.
+//!
+//! There is one exception to the above rule: `llvm.dbg.declare` instruction
+//! must be linked to the source location of the variable being declared. For
+//! function parameters these `llvm.dbg.declare` instructions typically occur
+//! in the middle of the prologue, however, they are ignored by LLVM's prologue
+//! detection. The `create_argument_metadata()` and related functions take care
+//! of linking the `llvm.dbg.declare` instructions to the correct source
+//! locations even while source location emission is still disabled, so there
+//! is no need to do anything special with source location handling here.
+//!
+//! ## Unique Type Identification
+//!
+//! In order for link-time optimization to work properly, LLVM needs a unique
+//! type identifier that tells it across compilation units which types are the
+//! same as others. This type identifier is created by
+//! `TypeMap::get_unique_type_id_of_type()` using the following algorithm:
+//!
+//! (1) Primitive types have their name as ID
+//! (2) Structs, enums and traits have a multipart identifier
+//!
+//! (1) The first part is the SVH (strict version hash) of the crate they
+//! were originally defined in
+//!
+//! (2) The second part is the ast::NodeId of the definition in their
+//! original crate
+//!
+//! (3) The final part is a concatenation of the type IDs of their concrete
+//! type arguments if they are generic types.
+//!
+//! (3) Tuple-, pointer and function types are structurally identified, which
+//! means that they are equivalent if their component types are equivalent
+//! (i.e., (i32, i32) is the same regardless in which crate it is used).
+//!
+//! This algorithm also provides a stable ID for types that are defined in one
+//! crate but instantiated from metadata within another crate. We just have to
+//! take care to always map crate and `NodeId`s back to the original crate
+//! context.
+//!
+//! As a side-effect these unique type IDs also help to solve a problem arising
+//! from lifetime parameters. Since lifetime parameters are completely omitted
+//! in debuginfo, more than one `Ty` instance may map to the same debuginfo
+//! type metadata, that is, some struct `Struct<'a>` may have N instantiations
+//! with different concrete substitutions for `'a`, and thus there will be N
+//! `Ty` instances for the type `Struct<'a>` even though it is not generic
+//! otherwise. Unfortunately this means that we cannot use `ty::type_id()` as
+//! cheap identifier for type metadata -- we have done this in the past, but it
+//! led to unnecessary metadata duplication in the best case and LLVM
+//! assertions in the worst. However, the unique type ID as described above
+//! *can* be used as identifier. Since it is comparatively expensive to
+//! construct, though, `ty::type_id()` is still used additionally as an
+//! optimization for cases where the exact same type has been seen before
+//! (which is most of the time).
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
new file mode 100644
index 0000000..29edd660
--- /dev/null
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -0,0 +1,71 @@
+// .debug_gdb_scripts binary section.
+
+use crate::llvm;
+
+use crate::builder::Builder;
+use crate::common::CodegenCx;
+use crate::value::Value;
+use rustc_codegen_ssa::traits::*;
+use rustc_middle::bug;
+use rustc_session::config::DebugInfo;
+
+use rustc_span::symbol::sym;
+
+/// Inserts a side-effect free instruction sequence that makes sure that the
+/// .debug_gdb_scripts global is referenced, so it isn't removed by the linker.
+pub fn insert_reference_to_gdb_debug_scripts_section_global(bx: &mut Builder<'_, '_, '_>) {
+ if needs_gdb_debug_scripts_section(bx) {
+ let gdb_debug_scripts_section = get_or_insert_gdb_debug_scripts_section_global(bx);
+ // Load just the first byte as that's all that's necessary to force
+ // LLVM to keep around the reference to the global.
+ let indices = [bx.const_i32(0), bx.const_i32(0)];
+ let element = bx.inbounds_gep(gdb_debug_scripts_section, &indices);
+ let volative_load_instruction = bx.volatile_load(element);
+ unsafe {
+ llvm::LLVMSetAlignment(volative_load_instruction, 1);
+ }
+ }
+}
+
+/// Allocates the global variable responsible for the .debug_gdb_scripts binary
+/// section.
+pub fn get_or_insert_gdb_debug_scripts_section_global(cx: &CodegenCx<'ll, '_>) -> &'ll Value {
+ let c_section_var_name = "__rustc_debug_gdb_scripts_section__\0";
+ let section_var_name = &c_section_var_name[..c_section_var_name.len() - 1];
+
+ let section_var =
+ unsafe { llvm::LLVMGetNamedGlobal(cx.llmod, c_section_var_name.as_ptr().cast()) };
+
+ section_var.unwrap_or_else(|| {
+ let section_name = b".debug_gdb_scripts\0";
+ let section_contents = b"\x01gdb_load_rust_pretty_printers.py\0";
+
+ unsafe {
+ let llvm_type = cx.type_array(cx.type_i8(), section_contents.len() as u64);
+
+ let section_var = cx
+ .define_global(section_var_name, llvm_type)
+ .unwrap_or_else(|| bug!("symbol `{}` is already defined", section_var_name));
+ llvm::LLVMSetSection(section_var, section_name.as_ptr().cast());
+ llvm::LLVMSetInitializer(section_var, cx.const_bytes(section_contents));
+ llvm::LLVMSetGlobalConstant(section_var, llvm::True);
+ llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global);
+ llvm::LLVMRustSetLinkage(section_var, llvm::Linkage::LinkOnceODRLinkage);
+ // This should make sure that the whole section is not larger than
+ // the string it contains. Otherwise we get a warning from GDB.
+ llvm::LLVMSetAlignment(section_var, 1);
+ section_var
+ }
+ })
+}
+
+pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
+ let omit_gdb_pretty_printer_section = cx
+ .tcx
+ .sess
+ .contains_name(&cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section);
+
+ !omit_gdb_pretty_printer_section
+ && cx.sess().opts.debuginfo != DebugInfo::None
+ && cx.sess().target.target.options.emit_debug_gdb_scripts
+}
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
new file mode 100644
index 0000000..987149c
--- /dev/null
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -0,0 +1,2584 @@
+use self::EnumTagInfo::*;
+use self::MemberDescriptionFactory::*;
+use self::RecursiveTypeDescription::*;
+
+use super::namespace::mangled_name_of_instance;
+use super::type_names::compute_debuginfo_type_name;
+use super::utils::{
+ create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit, DIB,
+};
+use super::CrateDebugContext;
+
+use crate::abi;
+use crate::common::CodegenCx;
+use crate::llvm;
+use crate::llvm::debuginfo::{
+ DIArray, DICompositeType, DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType,
+ DebugEmissionKind,
+};
+use crate::value::Value;
+
+use rustc_ast as ast;
+use rustc_codegen_ssa::traits::*;
+use rustc_data_structures::const_cstr;
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_fs_util::path_to_c_string;
+use rustc_hir::def::CtorKind;
+use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
+use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::ich::NodeIdHashingMode;
+use rustc_middle::mir::interpret::truncate;
+use rustc_middle::mir::{self, Field, GeneratorLayout};
+use rustc_middle::ty::layout::{self, IntegerExt, PrimitiveExt, TyAndLayout};
+use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::Instance;
+use rustc_middle::ty::{self, AdtKind, GeneratorSubsts, ParamEnv, Ty, TyCtxt};
+use rustc_middle::{bug, span_bug};
+use rustc_session::config::{self, DebugInfo};
+use rustc_span::symbol::{Interner, Symbol};
+use rustc_span::{self, SourceFile, SourceFileHash, Span};
+use rustc_target::abi::{Abi, Align, HasDataLayout, Integer, LayoutOf, TagEncoding};
+use rustc_target::abi::{Int, Pointer, F32, F64};
+use rustc_target::abi::{Primitive, Size, VariantIdx, Variants};
+use tracing::debug;
+
+use libc::{c_longlong, c_uint};
+use std::collections::hash_map::Entry;
+use std::fmt::{self, Write};
+use std::hash::{Hash, Hasher};
+use std::iter;
+use std::path::{Path, PathBuf};
+use std::ptr;
+
+impl PartialEq for llvm::Metadata {
+ fn eq(&self, other: &Self) -> bool {
+ ptr::eq(self, other)
+ }
+}
+
+impl Eq for llvm::Metadata {}
+
+impl Hash for llvm::Metadata {
+ fn hash<H: Hasher>(&self, hasher: &mut H) {
+ (self as *const Self).hash(hasher);
+ }
+}
+
+impl fmt::Debug for llvm::Metadata {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ (self as *const Self).fmt(f)
+ }
+}
+
+// From DWARF 5.
+// See http://www.dwarfstd.org/ShowIssue.php?issue=140129.1.
+const DW_LANG_RUST: c_uint = 0x1c;
+#[allow(non_upper_case_globals)]
+const DW_ATE_boolean: c_uint = 0x02;
+#[allow(non_upper_case_globals)]
+const DW_ATE_float: c_uint = 0x04;
+#[allow(non_upper_case_globals)]
+const DW_ATE_signed: c_uint = 0x05;
+#[allow(non_upper_case_globals)]
+const DW_ATE_unsigned: c_uint = 0x07;
+#[allow(non_upper_case_globals)]
+const DW_ATE_unsigned_char: c_uint = 0x08;
+
+pub const UNKNOWN_LINE_NUMBER: c_uint = 0;
+pub const UNKNOWN_COLUMN_NUMBER: c_uint = 0;
+
+pub const NO_SCOPE_METADATA: Option<&DIScope> = None;
+
+#[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)]
+pub struct UniqueTypeId(Symbol);
+
+/// The `TypeMap` is where the `CrateDebugContext` holds the type metadata nodes
+/// created so far. The metadata nodes are indexed by `UniqueTypeId`, and, for
+/// faster lookup, also by `Ty`. The `TypeMap` is responsible for creating
+/// `UniqueTypeId`s.
+#[derive(Default)]
+pub struct TypeMap<'ll, 'tcx> {
+ /// The `UniqueTypeId`s created so far.
+ unique_id_interner: Interner,
+ /// A map from `UniqueTypeId` to debuginfo metadata for that type. This is a 1:1 mapping.
+ unique_id_to_metadata: FxHashMap<UniqueTypeId, &'ll DIType>,
+ /// A map from types to debuginfo metadata. This is an N:1 mapping.
+ type_to_metadata: FxHashMap<Ty<'tcx>, &'ll DIType>,
+ /// A map from types to `UniqueTypeId`. This is an N:1 mapping.
+ type_to_unique_id: FxHashMap<Ty<'tcx>, UniqueTypeId>,
+}
+
+impl TypeMap<'ll, 'tcx> {
+ /// Adds a Ty to metadata mapping to the TypeMap. The method will fail if
+ /// the mapping already exists.
+ fn register_type_with_metadata(&mut self, type_: Ty<'tcx>, metadata: &'ll DIType) {
+ if self.type_to_metadata.insert(type_, metadata).is_some() {
+ bug!("type metadata for `Ty` '{}' is already in the `TypeMap`!", type_);
+ }
+ }
+
+ /// Removes a `Ty`-to-metadata mapping.
+ /// This is useful when computing the metadata for a potentially
+ /// recursive type (e.g., a function pointer of the form:
+ ///
+ /// fn foo() -> impl Copy { foo }
+ ///
+ /// This kind of type cannot be properly represented
+ /// via LLVM debuginfo. As a workaround,
+ /// we register a temporary Ty to metadata mapping
+ /// for the function before we compute its actual metadata.
+ /// If the metadata computation ends up recursing back to the
+ /// original function, it will use the temporary mapping
+ /// for the inner self-reference, preventing us from
+ /// recursing forever.
+ ///
+ /// This function is used to remove the temporary metadata
+ /// mapping after we've computed the actual metadata.
+ fn remove_type(&mut self, type_: Ty<'tcx>) {
+ if self.type_to_metadata.remove(type_).is_none() {
+ bug!("type metadata `Ty` '{}' is not in the `TypeMap`!", type_);
+ }
+ }
+
+ /// Adds a `UniqueTypeId` to metadata mapping to the `TypeMap`. The method will
+ /// fail if the mapping already exists.
+ fn register_unique_id_with_metadata(
+ &mut self,
+ unique_type_id: UniqueTypeId,
+ metadata: &'ll DIType,
+ ) {
+ if self.unique_id_to_metadata.insert(unique_type_id, metadata).is_some() {
+ bug!(
+ "type metadata for unique ID '{}' is already in the `TypeMap`!",
+ self.get_unique_type_id_as_string(unique_type_id)
+ );
+ }
+ }
+
+ fn find_metadata_for_type(&self, type_: Ty<'tcx>) -> Option<&'ll DIType> {
+ self.type_to_metadata.get(&type_).cloned()
+ }
+
+ fn find_metadata_for_unique_id(&self, unique_type_id: UniqueTypeId) -> Option<&'ll DIType> {
+ self.unique_id_to_metadata.get(&unique_type_id).cloned()
+ }
+
+ /// Gets the string representation of a `UniqueTypeId`. This method will fail if
+ /// the ID is unknown.
+ fn get_unique_type_id_as_string(&self, unique_type_id: UniqueTypeId) -> &str {
+ let UniqueTypeId(interner_key) = unique_type_id;
+ self.unique_id_interner.get(interner_key)
+ }
+
+ /// Gets the `UniqueTypeId` for the given type. If the `UniqueTypeId` for the given
+ /// type has been requested before, this is just a table lookup. Otherwise, an
+ /// ID will be generated and stored for later lookup.
+ fn get_unique_type_id_of_type<'a>(
+ &mut self,
+ cx: &CodegenCx<'a, 'tcx>,
+ type_: Ty<'tcx>,
+ ) -> UniqueTypeId {
+ // Let's see if we already have something in the cache.
+ if let Some(unique_type_id) = self.type_to_unique_id.get(&type_).cloned() {
+ return unique_type_id;
+ }
+ // If not, generate one.
+
+ // The hasher we are using to generate the UniqueTypeId. We want
+ // something that provides more than the 64 bits of the DefaultHasher.
+ let mut hasher = StableHasher::new();
+ let mut hcx = cx.tcx.create_stable_hashing_context();
+ let type_ = cx.tcx.erase_regions(&type_);
+ hcx.while_hashing_spans(false, |hcx| {
+ hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+ type_.hash_stable(hcx, &mut hasher);
+ });
+ });
+ let unique_type_id = hasher.finish::<Fingerprint>().to_hex();
+
+ let key = self.unique_id_interner.intern(&unique_type_id);
+ self.type_to_unique_id.insert(type_, UniqueTypeId(key));
+
+ UniqueTypeId(key)
+ }
+
+ /// Gets the `UniqueTypeId` for an enum variant. Enum variants are not really
+ /// types of their own, so they need special handling. We still need a
+ /// `UniqueTypeId` for them, since to debuginfo they *are* real types.
+ fn get_unique_type_id_of_enum_variant<'a>(
+ &mut self,
+ cx: &CodegenCx<'a, 'tcx>,
+ enum_type: Ty<'tcx>,
+ variant_name: &str,
+ ) -> UniqueTypeId {
+ let enum_type_id = self.get_unique_type_id_of_type(cx, enum_type);
+ let enum_variant_type_id =
+ format!("{}::{}", self.get_unique_type_id_as_string(enum_type_id), variant_name);
+ let interner_key = self.unique_id_interner.intern(&enum_variant_type_id);
+ UniqueTypeId(interner_key)
+ }
+
+ /// Gets the unique type ID string for an enum variant part.
+ /// Variant parts are not types and shouldn't really have their own ID,
+ /// but it makes `set_members_of_composite_type()` simpler.
+ fn get_unique_type_id_str_of_enum_variant_part(
+ &mut self,
+ enum_type_id: UniqueTypeId,
+ ) -> String {
+ format!("{}_variant_part", self.get_unique_type_id_as_string(enum_type_id))
+ }
+}
+
+/// A description of some recursive type. It can either be already finished (as
+/// with `FinalMetadata`) or it is not yet finished, but contains all information
+/// needed to generate the missing parts of the description. See the
+/// documentation section on Recursive Types at the top of this file for more
+/// information.
+enum RecursiveTypeDescription<'ll, 'tcx> {
+ UnfinishedMetadata {
+ unfinished_type: Ty<'tcx>,
+ unique_type_id: UniqueTypeId,
+ metadata_stub: &'ll DICompositeType,
+ member_holding_stub: &'ll DICompositeType,
+ member_description_factory: MemberDescriptionFactory<'ll, 'tcx>,
+ },
+ FinalMetadata(&'ll DICompositeType),
+}
+
+fn create_and_register_recursive_type_forward_declaration(
+ cx: &CodegenCx<'ll, 'tcx>,
+ unfinished_type: Ty<'tcx>,
+ unique_type_id: UniqueTypeId,
+ metadata_stub: &'ll DICompositeType,
+ member_holding_stub: &'ll DICompositeType,
+ member_description_factory: MemberDescriptionFactory<'ll, 'tcx>,
+) -> RecursiveTypeDescription<'ll, 'tcx> {
+ // Insert the stub into the `TypeMap` in order to allow for recursive references.
+ let mut type_map = debug_context(cx).type_map.borrow_mut();
+ type_map.register_unique_id_with_metadata(unique_type_id, metadata_stub);
+ type_map.register_type_with_metadata(unfinished_type, metadata_stub);
+
+ UnfinishedMetadata {
+ unfinished_type,
+ unique_type_id,
+ metadata_stub,
+ member_holding_stub,
+ member_description_factory,
+ }
+}
+
+impl RecursiveTypeDescription<'ll, 'tcx> {
+ /// Finishes up the description of the type in question (mostly by providing
+ /// descriptions of the fields of the given type) and returns the final type
+ /// metadata.
+ fn finalize(&self, cx: &CodegenCx<'ll, 'tcx>) -> MetadataCreationResult<'ll> {
+ match *self {
+ FinalMetadata(metadata) => MetadataCreationResult::new(metadata, false),
+ UnfinishedMetadata {
+ unfinished_type,
+ unique_type_id,
+ metadata_stub,
+ member_holding_stub,
+ ref member_description_factory,
+ } => {
+ // Make sure that we have a forward declaration of the type in
+ // the TypeMap so that recursive references are possible. This
+ // will always be the case if the RecursiveTypeDescription has
+ // been properly created through the
+ // `create_and_register_recursive_type_forward_declaration()`
+ // function.
+ {
+ let type_map = debug_context(cx).type_map.borrow();
+ if type_map.find_metadata_for_unique_id(unique_type_id).is_none()
+ || type_map.find_metadata_for_type(unfinished_type).is_none()
+ {
+ bug!(
+ "Forward declaration of potentially recursive type \
+ '{:?}' was not found in TypeMap!",
+ unfinished_type
+ );
+ }
+ }
+
+ // ... then create the member descriptions ...
+ let member_descriptions = member_description_factory.create_member_descriptions(cx);
+
+ // ... and attach them to the stub to complete it.
+ set_members_of_composite_type(
+ cx,
+ unfinished_type,
+ member_holding_stub,
+ member_descriptions,
+ );
+ MetadataCreationResult::new(metadata_stub, true)
+ }
+ }
+ }
+}
+
+/// Returns from the enclosing function if the type metadata with the given
+/// unique ID can be found in the type map.
+macro_rules! return_if_metadata_created_in_meantime {
+ ($cx: expr, $unique_type_id: expr) => {
+ if let Some(metadata) =
+ debug_context($cx).type_map.borrow().find_metadata_for_unique_id($unique_type_id)
+ {
+ return MetadataCreationResult::new(metadata, true);
+ }
+ };
+}
+
+fn fixed_vec_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ unique_type_id: UniqueTypeId,
+ array_or_slice_type: Ty<'tcx>,
+ element_type: Ty<'tcx>,
+ span: Span,
+) -> MetadataCreationResult<'ll> {
+ let element_type_metadata = type_metadata(cx, element_type, span);
+
+ return_if_metadata_created_in_meantime!(cx, unique_type_id);
+
+ let (size, align) = cx.size_and_align_of(array_or_slice_type);
+
+ let upper_bound = match array_or_slice_type.kind() {
+ ty::Array(_, len) => len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong,
+ _ => -1,
+ };
+
+ let subrange =
+ unsafe { Some(llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound)) };
+
+ let subscripts = create_DIArray(DIB(cx), &[subrange]);
+ let metadata = unsafe {
+ llvm::LLVMRustDIBuilderCreateArrayType(
+ DIB(cx),
+ size.bits(),
+ align.bits() as u32,
+ element_type_metadata,
+ subscripts,
+ )
+ };
+
+ MetadataCreationResult::new(metadata, false)
+}
+
+fn vec_slice_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ slice_ptr_type: Ty<'tcx>,
+ element_type: Ty<'tcx>,
+ unique_type_id: UniqueTypeId,
+ span: Span,
+) -> MetadataCreationResult<'ll> {
+ let data_ptr_type = cx.tcx.mk_imm_ptr(element_type);
+
+ let data_ptr_metadata = type_metadata(cx, data_ptr_type, span);
+
+ return_if_metadata_created_in_meantime!(cx, unique_type_id);
+
+ let slice_type_name = compute_debuginfo_type_name(cx.tcx, slice_ptr_type, true);
+
+ let (pointer_size, pointer_align) = cx.size_and_align_of(data_ptr_type);
+ let (usize_size, usize_align) = cx.size_and_align_of(cx.tcx.types.usize);
+
+ let member_descriptions = vec![
+ MemberDescription {
+ name: "data_ptr".to_owned(),
+ type_metadata: data_ptr_metadata,
+ offset: Size::ZERO,
+ size: pointer_size,
+ align: pointer_align,
+ flags: DIFlags::FlagZero,
+ discriminant: None,
+ source_info: None,
+ },
+ MemberDescription {
+ name: "length".to_owned(),
+ type_metadata: type_metadata(cx, cx.tcx.types.usize, span),
+ offset: pointer_size,
+ size: usize_size,
+ align: usize_align,
+ flags: DIFlags::FlagZero,
+ discriminant: None,
+ source_info: None,
+ },
+ ];
+
+ let file_metadata = unknown_file_metadata(cx);
+
+ let metadata = composite_type_metadata(
+ cx,
+ slice_ptr_type,
+ &slice_type_name[..],
+ unique_type_id,
+ member_descriptions,
+ NO_SCOPE_METADATA,
+ file_metadata,
+ span,
+ );
+ MetadataCreationResult::new(metadata, false)
+}
+
+fn subroutine_type_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ unique_type_id: UniqueTypeId,
+ signature: ty::PolyFnSig<'tcx>,
+ span: Span,
+) -> MetadataCreationResult<'ll> {
+ let signature =
+ cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &signature);
+
+ let signature_metadata: Vec<_> = iter::once(
+ // return type
+ match signature.output().kind() {
+ ty::Tuple(ref tys) if tys.is_empty() => None,
+ _ => Some(type_metadata(cx, signature.output(), span)),
+ },
+ )
+ .chain(
+ // regular arguments
+ signature.inputs().iter().map(|argument_type| Some(type_metadata(cx, argument_type, span))),
+ )
+ .collect();
+
+ return_if_metadata_created_in_meantime!(cx, unique_type_id);
+
+ MetadataCreationResult::new(
+ unsafe {
+ llvm::LLVMRustDIBuilderCreateSubroutineType(
+ DIB(cx),
+ create_DIArray(DIB(cx), &signature_metadata[..]),
+ )
+ },
+ false,
+ )
+}
+
+// FIXME(1563): This is all a bit of a hack because 'trait pointer' is an ill-
+// defined concept. For the case of an actual trait pointer (i.e., `Box<Trait>`,
+// `&Trait`), `trait_object_type` should be the whole thing (e.g, `Box<Trait>`) and
+// `trait_type` should be the actual trait (e.g., `Trait`). Where the trait is part
+// of a DST struct, there is no `trait_object_type` and the results of this
+// function will be a little bit weird.
+fn trait_pointer_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ trait_type: Ty<'tcx>,
+ trait_object_type: Option<Ty<'tcx>>,
+ unique_type_id: UniqueTypeId,
+) -> &'ll DIType {
+ // The implementation provided here is a stub. It makes sure that the trait
+ // type is assigned the correct name, size, namespace, and source location.
+ // However, it does not describe the trait's methods.
+
+ let containing_scope = match trait_type.kind() {
+ ty::Dynamic(ref data, ..) => {
+ data.principal_def_id().map(|did| get_namespace_for_item(cx, did))
+ }
+ _ => {
+ bug!(
+ "debuginfo: unexpected trait-object type in \
+ trait_pointer_metadata(): {:?}",
+ trait_type
+ );
+ }
+ };
+
+ let trait_object_type = trait_object_type.unwrap_or(trait_type);
+ let trait_type_name = compute_debuginfo_type_name(cx.tcx, trait_object_type, false);
+
+ let file_metadata = unknown_file_metadata(cx);
+
+ let layout = cx.layout_of(cx.tcx.mk_mut_ptr(trait_type));
+
+ assert_eq!(abi::FAT_PTR_ADDR, 0);
+ assert_eq!(abi::FAT_PTR_EXTRA, 1);
+
+ let data_ptr_field = layout.field(cx, 0);
+ let vtable_field = layout.field(cx, 1);
+ let member_descriptions = vec![
+ MemberDescription {
+ name: "pointer".to_owned(),
+ type_metadata: type_metadata(
+ cx,
+ cx.tcx.mk_mut_ptr(cx.tcx.types.u8),
+ rustc_span::DUMMY_SP,
+ ),
+ offset: layout.fields.offset(0),
+ size: data_ptr_field.size,
+ align: data_ptr_field.align.abi,
+ flags: DIFlags::FlagArtificial,
+ discriminant: None,
+ source_info: None,
+ },
+ MemberDescription {
+ name: "vtable".to_owned(),
+ type_metadata: type_metadata(cx, vtable_field.ty, rustc_span::DUMMY_SP),
+ offset: layout.fields.offset(1),
+ size: vtable_field.size,
+ align: vtable_field.align.abi,
+ flags: DIFlags::FlagArtificial,
+ discriminant: None,
+ source_info: None,
+ },
+ ];
+
+ composite_type_metadata(
+ cx,
+ trait_object_type,
+ &trait_type_name[..],
+ unique_type_id,
+ member_descriptions,
+ containing_scope,
+ file_metadata,
+ rustc_span::DUMMY_SP,
+ )
+}
+
+pub fn type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, usage_site_span: Span) -> &'ll DIType {
+ // Get the unique type ID of this type.
+ let unique_type_id = {
+ let mut type_map = debug_context(cx).type_map.borrow_mut();
+ // First, try to find the type in `TypeMap`. If we have seen it before, we
+ // can exit early here.
+ match type_map.find_metadata_for_type(t) {
+ Some(metadata) => {
+ return metadata;
+ }
+ None => {
+ // The Ty is not in the `TypeMap` but maybe we have already seen
+ // an equivalent type (e.g., only differing in region arguments).
+ // In order to find out, generate the unique type ID and look
+ // that up.
+ let unique_type_id = type_map.get_unique_type_id_of_type(cx, t);
+ match type_map.find_metadata_for_unique_id(unique_type_id) {
+ Some(metadata) => {
+ // There is already an equivalent type in the TypeMap.
+ // Register this Ty as an alias in the cache and
+ // return the cached metadata.
+ type_map.register_type_with_metadata(t, metadata);
+ return metadata;
+ }
+ None => {
+ // There really is no type metadata for this type, so
+ // proceed by creating it.
+ unique_type_id
+ }
+ }
+ }
+ }
+ };
+
+ debug!("type_metadata: {:?}", t);
+
+ let ptr_metadata = |ty: Ty<'tcx>| match *ty.kind() {
+ ty::Slice(typ) => Ok(vec_slice_metadata(cx, t, typ, unique_type_id, usage_site_span)),
+ ty::Str => Ok(vec_slice_metadata(cx, t, cx.tcx.types.u8, unique_type_id, usage_site_span)),
+ ty::Dynamic(..) => Ok(MetadataCreationResult::new(
+ trait_pointer_metadata(cx, ty, Some(t), unique_type_id),
+ false,
+ )),
+ _ => {
+ let pointee_metadata = type_metadata(cx, ty, usage_site_span);
+
+ if let Some(metadata) =
+ debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id)
+ {
+ return Err(metadata);
+ }
+
+ Ok(MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata), false))
+ }
+ };
+
+ let MetadataCreationResult { metadata, already_stored_in_typemap } = match *t.kind() {
+ ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
+ MetadataCreationResult::new(basic_type_metadata(cx, t), false)
+ }
+ ty::Tuple(ref elements) if elements.is_empty() => {
+ MetadataCreationResult::new(basic_type_metadata(cx, t), false)
+ }
+ ty::Array(typ, _) | ty::Slice(typ) => {
+ fixed_vec_metadata(cx, unique_type_id, t, typ, usage_site_span)
+ }
+ ty::Str => fixed_vec_metadata(cx, unique_type_id, t, cx.tcx.types.i8, usage_site_span),
+ ty::Dynamic(..) => {
+ MetadataCreationResult::new(trait_pointer_metadata(cx, t, None, unique_type_id), false)
+ }
+ ty::Foreign(..) => {
+ MetadataCreationResult::new(foreign_type_metadata(cx, t, unique_type_id), false)
+ }
+ ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => match ptr_metadata(ty) {
+ Ok(res) => res,
+ Err(metadata) => return metadata,
+ },
+ ty::Adt(def, _) if def.is_box() => match ptr_metadata(t.boxed_ty()) {
+ Ok(res) => res,
+ Err(metadata) => return metadata,
+ },
+ ty::FnDef(..) | ty::FnPtr(_) => {
+ if let Some(metadata) =
+ debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id)
+ {
+ return metadata;
+ }
+
+ // It's possible to create a self-referential
+ // type in Rust by using 'impl trait':
+ //
+ // fn foo() -> impl Copy { foo }
+ //
+ // See `TypeMap::remove_type` for more detals
+ // about the workaround.
+
+ let temp_type = {
+ unsafe {
+ // The choice of type here is pretty arbitrary -
+ // anything reading the debuginfo for a recursive
+ // type is going to see *something* weird - the only
+ // question is what exactly it will see.
+ let name = "<recur_type>";
+ llvm::LLVMRustDIBuilderCreateBasicType(
+ DIB(cx),
+ name.as_ptr().cast(),
+ name.len(),
+ cx.size_of(t).bits(),
+ DW_ATE_unsigned,
+ )
+ }
+ };
+
+ let type_map = &debug_context(cx).type_map;
+ type_map.borrow_mut().register_type_with_metadata(t, temp_type);
+
+ let fn_metadata =
+ subroutine_type_metadata(cx, unique_type_id, t.fn_sig(cx.tcx), usage_site_span)
+ .metadata;
+
+ type_map.borrow_mut().remove_type(t);
+
+ // This is actually a function pointer, so wrap it in pointer DI.
+ MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false)
+ }
+ ty::Closure(def_id, substs) => {
+ let upvar_tys: Vec<_> = substs.as_closure().upvar_tys().collect();
+ let containing_scope = get_namespace_for_item(cx, def_id);
+ prepare_tuple_metadata(
+ cx,
+ t,
+ &upvar_tys,
+ unique_type_id,
+ usage_site_span,
+ Some(containing_scope),
+ )
+ .finalize(cx)
+ }
+ ty::Generator(def_id, substs, _) => {
+ let upvar_tys: Vec<_> = substs
+ .as_generator()
+ .prefix_tys()
+ .map(|t| cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t))
+ .collect();
+ prepare_enum_metadata(cx, t, def_id, unique_type_id, usage_site_span, upvar_tys)
+ .finalize(cx)
+ }
+ ty::Adt(def, ..) => match def.adt_kind() {
+ AdtKind::Struct => {
+ prepare_struct_metadata(cx, t, unique_type_id, usage_site_span).finalize(cx)
+ }
+ AdtKind::Union => {
+ prepare_union_metadata(cx, t, unique_type_id, usage_site_span).finalize(cx)
+ }
+ AdtKind::Enum => {
+ prepare_enum_metadata(cx, t, def.did, unique_type_id, usage_site_span, vec![])
+ .finalize(cx)
+ }
+ },
+ ty::Tuple(ref elements) => {
+ let tys: Vec<_> = elements.iter().map(|k| k.expect_ty()).collect();
+ prepare_tuple_metadata(cx, t, &tys, unique_type_id, usage_site_span, NO_SCOPE_METADATA)
+ .finalize(cx)
+ }
+ // Type parameters from polymorphized functions.
+ ty::Param(_) => MetadataCreationResult::new(param_type_metadata(cx, t), false),
+ _ => bug!("debuginfo: unexpected type in type_metadata: {:?}", t),
+ };
+
+ {
+ let mut type_map = debug_context(cx).type_map.borrow_mut();
+
+ if already_stored_in_typemap {
+ // Also make sure that we already have a `TypeMap` entry for the unique type ID.
+ let metadata_for_uid = match type_map.find_metadata_for_unique_id(unique_type_id) {
+ Some(metadata) => metadata,
+ None => {
+ span_bug!(
+ usage_site_span,
+ "expected type metadata for unique \
+ type ID '{}' to already be in \
+ the `debuginfo::TypeMap` but it \
+ was not. (Ty = {})",
+ type_map.get_unique_type_id_as_string(unique_type_id),
+ t
+ );
+ }
+ };
+
+ match type_map.find_metadata_for_type(t) {
+ Some(metadata) => {
+ if metadata != metadata_for_uid {
+ span_bug!(
+ usage_site_span,
+ "mismatch between `Ty` and \
+ `UniqueTypeId` maps in \
+ `debuginfo::TypeMap`. \
+ UniqueTypeId={}, Ty={}",
+ type_map.get_unique_type_id_as_string(unique_type_id),
+ t
+ );
+ }
+ }
+ None => {
+ type_map.register_type_with_metadata(t, metadata);
+ }
+ }
+ } else {
+ type_map.register_type_with_metadata(t, metadata);
+ type_map.register_unique_id_with_metadata(unique_type_id, metadata);
+ }
+ }
+
+ metadata
+}
+
+fn hex_encode(data: &[u8]) -> String {
+ let mut hex_string = String::with_capacity(data.len() * 2);
+ for byte in data.iter() {
+ write!(&mut hex_string, "{:02x}", byte).unwrap();
+ }
+ hex_string
+}
+
+pub fn file_metadata(
+ cx: &CodegenCx<'ll, '_>,
+ source_file: &SourceFile,
+ defining_crate: CrateNum,
+) -> &'ll DIFile {
+ debug!("file_metadata: file_name: {}, defining_crate: {}", source_file.name, defining_crate);
+
+ let hash = Some(&source_file.src_hash);
+ let file_name = Some(source_file.name.to_string());
+ let directory = if defining_crate == LOCAL_CRATE {
+ Some(cx.sess().working_dir.0.to_string_lossy().to_string())
+ } else {
+ // If the path comes from an upstream crate we assume it has been made
+ // independent of the compiler's working directory one way or another.
+ None
+ };
+ file_metadata_raw(cx, file_name, directory, hash)
+}
+
+pub fn unknown_file_metadata(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile {
+ file_metadata_raw(cx, None, None, None)
+}
+
+fn file_metadata_raw(
+ cx: &CodegenCx<'ll, '_>,
+ file_name: Option<String>,
+ directory: Option<String>,
+ hash: Option<&SourceFileHash>,
+) -> &'ll DIFile {
+ let key = (file_name, directory);
+
+ match debug_context(cx).created_files.borrow_mut().entry(key) {
+ Entry::Occupied(o) => o.get(),
+ Entry::Vacant(v) => {
+ let (file_name, directory) = v.key();
+ debug!("file_metadata: file_name: {:?}, directory: {:?}", file_name, directory);
+
+ let file_name = file_name.as_deref().unwrap_or("<unknown>");
+ let directory = directory.as_deref().unwrap_or("");
+
+ let (hash_kind, hash_value) = match hash {
+ Some(hash) => {
+ let kind = match hash.kind {
+ rustc_span::SourceFileHashAlgorithm::Md5 => llvm::ChecksumKind::MD5,
+ rustc_span::SourceFileHashAlgorithm::Sha1 => llvm::ChecksumKind::SHA1,
+ };
+ (kind, hex_encode(hash.hash_bytes()))
+ }
+ None => (llvm::ChecksumKind::None, String::new()),
+ };
+
+ let file_metadata = unsafe {
+ llvm::LLVMRustDIBuilderCreateFile(
+ DIB(cx),
+ file_name.as_ptr().cast(),
+ file_name.len(),
+ directory.as_ptr().cast(),
+ directory.len(),
+ hash_kind,
+ hash_value.as_ptr().cast(),
+ hash_value.len(),
+ )
+ };
+
+ v.insert(file_metadata);
+ file_metadata
+ }
+ }
+}
+
+trait MsvcBasicName {
+ fn msvc_basic_name(self) -> &'static str;
+}
+
+impl MsvcBasicName for ast::IntTy {
+ fn msvc_basic_name(self) -> &'static str {
+ match self {
+ ast::IntTy::Isize => "ptrdiff_t",
+ ast::IntTy::I8 => "__int8",
+ ast::IntTy::I16 => "__int16",
+ ast::IntTy::I32 => "__int32",
+ ast::IntTy::I64 => "__int64",
+ ast::IntTy::I128 => "__int128",
+ }
+ }
+}
+
+impl MsvcBasicName for ast::UintTy {
+ fn msvc_basic_name(self) -> &'static str {
+ match self {
+ ast::UintTy::Usize => "size_t",
+ ast::UintTy::U8 => "unsigned __int8",
+ ast::UintTy::U16 => "unsigned __int16",
+ ast::UintTy::U32 => "unsigned __int32",
+ ast::UintTy::U64 => "unsigned __int64",
+ ast::UintTy::U128 => "unsigned __int128",
+ }
+ }
+}
+
+impl MsvcBasicName for ast::FloatTy {
+ fn msvc_basic_name(self) -> &'static str {
+ match self {
+ ast::FloatTy::F32 => "float",
+ ast::FloatTy::F64 => "double",
+ }
+ }
+}
+
+fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
+ debug!("basic_type_metadata: {:?}", t);
+
+ // When targeting MSVC, emit MSVC style type names for compatibility with
+ // .natvis visualizers (and perhaps other existing native debuggers?)
+ let msvc_like_names = cx.tcx.sess.target.target.options.is_like_msvc;
+
+ let (name, encoding) = match t.kind() {
+ ty::Never => ("!", DW_ATE_unsigned),
+ ty::Tuple(ref elements) if elements.is_empty() => ("()", DW_ATE_unsigned),
+ ty::Bool => ("bool", DW_ATE_boolean),
+ ty::Char => ("char", DW_ATE_unsigned_char),
+ ty::Int(int_ty) if msvc_like_names => (int_ty.msvc_basic_name(), DW_ATE_signed),
+ ty::Uint(uint_ty) if msvc_like_names => (uint_ty.msvc_basic_name(), DW_ATE_unsigned),
+ ty::Float(float_ty) if msvc_like_names => (float_ty.msvc_basic_name(), DW_ATE_float),
+ ty::Int(int_ty) => (int_ty.name_str(), DW_ATE_signed),
+ ty::Uint(uint_ty) => (uint_ty.name_str(), DW_ATE_unsigned),
+ ty::Float(float_ty) => (float_ty.name_str(), DW_ATE_float),
+ _ => bug!("debuginfo::basic_type_metadata - `t` is invalid type"),
+ };
+
+ let ty_metadata = unsafe {
+ llvm::LLVMRustDIBuilderCreateBasicType(
+ DIB(cx),
+ name.as_ptr().cast(),
+ name.len(),
+ cx.size_of(t).bits(),
+ encoding,
+ )
+ };
+
+ if !msvc_like_names {
+ return ty_metadata;
+ }
+
+ let typedef_name = match t.kind() {
+ ty::Int(int_ty) => int_ty.name_str(),
+ ty::Uint(uint_ty) => uint_ty.name_str(),
+ ty::Float(float_ty) => float_ty.name_str(),
+ _ => return ty_metadata,
+ };
+
+ let typedef_metadata = unsafe {
+ llvm::LLVMRustDIBuilderCreateTypedef(
+ DIB(cx),
+ ty_metadata,
+ typedef_name.as_ptr().cast(),
+ typedef_name.len(),
+ unknown_file_metadata(cx),
+ 0,
+ None,
+ )
+ };
+
+ typedef_metadata
+}
+
+fn foreign_type_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ t: Ty<'tcx>,
+ unique_type_id: UniqueTypeId,
+) -> &'ll DIType {
+ debug!("foreign_type_metadata: {:?}", t);
+
+ let name = compute_debuginfo_type_name(cx.tcx, t, false);
+ create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA, DIFlags::FlagZero)
+}
+
+fn pointer_type_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ pointer_type: Ty<'tcx>,
+ pointee_type_metadata: &'ll DIType,
+) -> &'ll DIType {
+ let (pointer_size, pointer_align) = cx.size_and_align_of(pointer_type);
+ let name = compute_debuginfo_type_name(cx.tcx, pointer_type, false);
+ unsafe {
+ llvm::LLVMRustDIBuilderCreatePointerType(
+ DIB(cx),
+ pointee_type_metadata,
+ pointer_size.bits(),
+ pointer_align.bits() as u32,
+ 0, // Ignore DWARF address space.
+ name.as_ptr().cast(),
+ name.len(),
+ )
+ }
+}
+
+fn param_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
+ debug!("param_type_metadata: {:?}", t);
+ let name = format!("{:?}", t);
+ unsafe {
+ llvm::LLVMRustDIBuilderCreateBasicType(
+ DIB(cx),
+ name.as_ptr().cast(),
+ name.len(),
+ Size::ZERO.bits(),
+ DW_ATE_unsigned,
+ )
+ }
+}
+
+pub fn compile_unit_metadata(
+ tcx: TyCtxt<'_>,
+ codegen_unit_name: &str,
+ debug_context: &CrateDebugContext<'ll, '_>,
+) -> &'ll DIDescriptor {
+ let mut name_in_debuginfo = match tcx.sess.local_crate_source_file {
+ Some(ref path) => path.clone(),
+ None => PathBuf::from(&*tcx.crate_name(LOCAL_CRATE).as_str()),
+ };
+
+ // The OSX linker has an idiosyncrasy where it will ignore some debuginfo
+ // if multiple object files with the same `DW_AT_name` are linked together.
+ // As a workaround we generate unique names for each object file. Those do
+ // not correspond to an actual source file but that should be harmless.
+ if tcx.sess.target.target.options.is_like_osx {
+ name_in_debuginfo.push("@");
+ name_in_debuginfo.push(codegen_unit_name);
+ }
+
+ debug!("compile_unit_metadata: {:?}", name_in_debuginfo);
+ let rustc_producer =
+ format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION"),);
+ // FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice.
+ let producer = format!("clang LLVM ({})", rustc_producer);
+
+ let name_in_debuginfo = name_in_debuginfo.to_string_lossy();
+ let work_dir = tcx.sess.working_dir.0.to_string_lossy();
+ let flags = "\0";
+ let split_name = "";
+
+ // FIXME(#60020):
+ //
+ // This should actually be
+ //
+ // let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo);
+ //
+ // That is, we should set LLVM's emission kind to `LineTablesOnly` if
+ // we are compiling with "limited" debuginfo. However, some of the
+ // existing tools relied on slightly more debuginfo being generated than
+ // would be the case with `LineTablesOnly`, and we did not want to break
+ // these tools in a "drive-by fix", without a good idea or plan about
+ // what limited debuginfo should exactly look like. So for now we keep
+ // the emission kind as `FullDebug`.
+ //
+ // See https://github.com/rust-lang/rust/issues/60020 for details.
+ let kind = DebugEmissionKind::FullDebug;
+ assert!(tcx.sess.opts.debuginfo != DebugInfo::None);
+
+ unsafe {
+ let file_metadata = llvm::LLVMRustDIBuilderCreateFile(
+ debug_context.builder,
+ name_in_debuginfo.as_ptr().cast(),
+ name_in_debuginfo.len(),
+ work_dir.as_ptr().cast(),
+ work_dir.len(),
+ llvm::ChecksumKind::None,
+ ptr::null(),
+ 0,
+ );
+
+ let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit(
+ debug_context.builder,
+ DW_LANG_RUST,
+ file_metadata,
+ producer.as_ptr().cast(),
+ producer.len(),
+ tcx.sess.opts.optimize != config::OptLevel::No,
+ flags.as_ptr().cast(),
+ 0,
+ split_name.as_ptr().cast(),
+ split_name.len(),
+ kind,
+ );
+
+ if tcx.sess.opts.debugging_opts.profile {
+ let cu_desc_metadata =
+ llvm::LLVMRustMetadataAsValue(debug_context.llcontext, unit_metadata);
+ let default_gcda_path = &tcx.output_filenames(LOCAL_CRATE).with_extension("gcda");
+ let gcda_path =
+ tcx.sess.opts.debugging_opts.profile_emit.as_ref().unwrap_or(default_gcda_path);
+
+ let gcov_cu_info = [
+ path_to_mdstring(
+ debug_context.llcontext,
+ &tcx.output_filenames(LOCAL_CRATE).with_extension("gcno"),
+ ),
+ path_to_mdstring(debug_context.llcontext, &gcda_path),
+ cu_desc_metadata,
+ ];
+ let gcov_metadata = llvm::LLVMMDNodeInContext(
+ debug_context.llcontext,
+ gcov_cu_info.as_ptr(),
+ gcov_cu_info.len() as c_uint,
+ );
+
+ let llvm_gcov_ident = const_cstr!("llvm.gcov");
+ llvm::LLVMAddNamedMetadataOperand(
+ debug_context.llmod,
+ llvm_gcov_ident.as_ptr(),
+ gcov_metadata,
+ );
+ }
+
+ // Insert `llvm.ident` metadata on the wasm32 targets since that will
+ // get hooked up to the "producer" sections `processed-by` information.
+ if tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
+ let name_metadata = llvm::LLVMMDStringInContext(
+ debug_context.llcontext,
+ rustc_producer.as_ptr().cast(),
+ rustc_producer.as_bytes().len() as c_uint,
+ );
+ llvm::LLVMAddNamedMetadataOperand(
+ debug_context.llmod,
+ const_cstr!("llvm.ident").as_ptr(),
+ llvm::LLVMMDNodeInContext(debug_context.llcontext, &name_metadata, 1),
+ );
+ }
+
+ return unit_metadata;
+ };
+
+ fn path_to_mdstring(llcx: &'ll llvm::Context, path: &Path) -> &'ll Value {
+ let path_str = path_to_c_string(path);
+ unsafe {
+ llvm::LLVMMDStringInContext(
+ llcx,
+ path_str.as_ptr(),
+ path_str.as_bytes().len() as c_uint,
+ )
+ }
+ }
+}
+
+struct MetadataCreationResult<'ll> {
+ metadata: &'ll DIType,
+ already_stored_in_typemap: bool,
+}
+
+impl MetadataCreationResult<'ll> {
+ fn new(metadata: &'ll DIType, already_stored_in_typemap: bool) -> Self {
+ MetadataCreationResult { metadata, already_stored_in_typemap }
+ }
+}
+
+#[derive(Debug)]
+struct SourceInfo<'ll> {
+ file: &'ll DIFile,
+ line: u32,
+}
+
+/// Description of a type member, which can either be a regular field (as in
+/// structs or tuples) or an enum variant.
+#[derive(Debug)]
+struct MemberDescription<'ll> {
+ name: String,
+ type_metadata: &'ll DIType,
+ offset: Size,
+ size: Size,
+ align: Align,
+ flags: DIFlags,
+ discriminant: Option<u64>,
+ source_info: Option<SourceInfo<'ll>>,
+}
+
+impl<'ll> MemberDescription<'ll> {
+ fn into_metadata(
+ self,
+ cx: &CodegenCx<'ll, '_>,
+ composite_type_metadata: &'ll DIScope,
+ ) -> &'ll DIType {
+ let (file, line) = self
+ .source_info
+ .map(|info| (info.file, info.line))
+ .unwrap_or_else(|| (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER));
+ unsafe {
+ llvm::LLVMRustDIBuilderCreateVariantMemberType(
+ DIB(cx),
+ composite_type_metadata,
+ self.name.as_ptr().cast(),
+ self.name.len(),
+ file,
+ line,
+ self.size.bits(),
+ self.align.bits() as u32,
+ self.offset.bits(),
+ match self.discriminant {
+ None => None,
+ Some(value) => Some(cx.const_u64(value)),
+ },
+ self.flags,
+ self.type_metadata,
+ )
+ }
+ }
+}
+
+/// A factory for `MemberDescription`s. It produces a list of member descriptions
+/// for some record-like type. `MemberDescriptionFactory`s are used to defer the
+/// creation of type member descriptions in order to break cycles arising from
+/// recursive type definitions.
+enum MemberDescriptionFactory<'ll, 'tcx> {
+ StructMDF(StructMemberDescriptionFactory<'tcx>),
+ TupleMDF(TupleMemberDescriptionFactory<'tcx>),
+ EnumMDF(EnumMemberDescriptionFactory<'ll, 'tcx>),
+ UnionMDF(UnionMemberDescriptionFactory<'tcx>),
+ VariantMDF(VariantMemberDescriptionFactory<'ll, 'tcx>),
+}
+
+impl MemberDescriptionFactory<'ll, 'tcx> {
+ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> {
+ match *self {
+ StructMDF(ref this) => this.create_member_descriptions(cx),
+ TupleMDF(ref this) => this.create_member_descriptions(cx),
+ EnumMDF(ref this) => this.create_member_descriptions(cx),
+ UnionMDF(ref this) => this.create_member_descriptions(cx),
+ VariantMDF(ref this) => this.create_member_descriptions(cx),
+ }
+ }
+}
+
+//=-----------------------------------------------------------------------------
+// Structs
+//=-----------------------------------------------------------------------------
+
+/// Creates `MemberDescription`s for the fields of a struct.
+struct StructMemberDescriptionFactory<'tcx> {
+ ty: Ty<'tcx>,
+ variant: &'tcx ty::VariantDef,
+ span: Span,
+}
+
+impl<'tcx> StructMemberDescriptionFactory<'tcx> {
+ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> {
+ let layout = cx.layout_of(self.ty);
+ self.variant
+ .fields
+ .iter()
+ .enumerate()
+ .map(|(i, f)| {
+ let name = if self.variant.ctor_kind == CtorKind::Fn {
+ format!("__{}", i)
+ } else {
+ f.ident.to_string()
+ };
+ let field = layout.field(cx, i);
+ MemberDescription {
+ name,
+ type_metadata: type_metadata(cx, field.ty, self.span),
+ offset: layout.fields.offset(i),
+ size: field.size,
+ align: field.align.abi,
+ flags: DIFlags::FlagZero,
+ discriminant: None,
+ source_info: None,
+ }
+ })
+ .collect()
+ }
+}
+
+fn prepare_struct_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ struct_type: Ty<'tcx>,
+ unique_type_id: UniqueTypeId,
+ span: Span,
+) -> RecursiveTypeDescription<'ll, 'tcx> {
+ let struct_name = compute_debuginfo_type_name(cx.tcx, struct_type, false);
+
+ let (struct_def_id, variant) = match struct_type.kind() {
+ ty::Adt(def, _) => (def.did, def.non_enum_variant()),
+ _ => bug!("prepare_struct_metadata on a non-ADT"),
+ };
+
+ let containing_scope = get_namespace_for_item(cx, struct_def_id);
+
+ let struct_metadata_stub = create_struct_stub(
+ cx,
+ struct_type,
+ &struct_name,
+ unique_type_id,
+ Some(containing_scope),
+ DIFlags::FlagZero,
+ );
+
+ create_and_register_recursive_type_forward_declaration(
+ cx,
+ struct_type,
+ unique_type_id,
+ struct_metadata_stub,
+ struct_metadata_stub,
+ StructMDF(StructMemberDescriptionFactory { ty: struct_type, variant, span }),
+ )
+}
+
+//=-----------------------------------------------------------------------------
+// Tuples
+//=-----------------------------------------------------------------------------
+
+/// Creates `MemberDescription`s for the fields of a tuple.
+struct TupleMemberDescriptionFactory<'tcx> {
+ ty: Ty<'tcx>,
+ component_types: Vec<Ty<'tcx>>,
+ span: Span,
+}
+
+impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
+ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> {
+ let layout = cx.layout_of(self.ty);
+ self.component_types
+ .iter()
+ .enumerate()
+ .map(|(i, &component_type)| {
+ let (size, align) = cx.size_and_align_of(component_type);
+ MemberDescription {
+ name: format!("__{}", i),
+ type_metadata: type_metadata(cx, component_type, self.span),
+ offset: layout.fields.offset(i),
+ size,
+ align,
+ flags: DIFlags::FlagZero,
+ discriminant: None,
+ source_info: None,
+ }
+ })
+ .collect()
+ }
+}
+
+fn prepare_tuple_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ tuple_type: Ty<'tcx>,
+ component_types: &[Ty<'tcx>],
+ unique_type_id: UniqueTypeId,
+ span: Span,
+ containing_scope: Option<&'ll DIScope>,
+) -> RecursiveTypeDescription<'ll, 'tcx> {
+ let tuple_name = compute_debuginfo_type_name(cx.tcx, tuple_type, false);
+
+ let struct_stub = create_struct_stub(
+ cx,
+ tuple_type,
+ &tuple_name[..],
+ unique_type_id,
+ containing_scope,
+ DIFlags::FlagZero,
+ );
+
+ create_and_register_recursive_type_forward_declaration(
+ cx,
+ tuple_type,
+ unique_type_id,
+ struct_stub,
+ struct_stub,
+ TupleMDF(TupleMemberDescriptionFactory {
+ ty: tuple_type,
+ component_types: component_types.to_vec(),
+ span,
+ }),
+ )
+}
+
+//=-----------------------------------------------------------------------------
+// Unions
+//=-----------------------------------------------------------------------------
+
+struct UnionMemberDescriptionFactory<'tcx> {
+ layout: TyAndLayout<'tcx>,
+ variant: &'tcx ty::VariantDef,
+ span: Span,
+}
+
+impl<'tcx> UnionMemberDescriptionFactory<'tcx> {
+ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> {
+ self.variant
+ .fields
+ .iter()
+ .enumerate()
+ .map(|(i, f)| {
+ let field = self.layout.field(cx, i);
+ MemberDescription {
+ name: f.ident.to_string(),
+ type_metadata: type_metadata(cx, field.ty, self.span),
+ offset: Size::ZERO,
+ size: field.size,
+ align: field.align.abi,
+ flags: DIFlags::FlagZero,
+ discriminant: None,
+ source_info: None,
+ }
+ })
+ .collect()
+ }
+}
+
+fn prepare_union_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ union_type: Ty<'tcx>,
+ unique_type_id: UniqueTypeId,
+ span: Span,
+) -> RecursiveTypeDescription<'ll, 'tcx> {
+ let union_name = compute_debuginfo_type_name(cx.tcx, union_type, false);
+
+ let (union_def_id, variant) = match union_type.kind() {
+ ty::Adt(def, _) => (def.did, def.non_enum_variant()),
+ _ => bug!("prepare_union_metadata on a non-ADT"),
+ };
+
+ let containing_scope = get_namespace_for_item(cx, union_def_id);
+
+ let union_metadata_stub =
+ create_union_stub(cx, union_type, &union_name, unique_type_id, containing_scope);
+
+ create_and_register_recursive_type_forward_declaration(
+ cx,
+ union_type,
+ unique_type_id,
+ union_metadata_stub,
+ union_metadata_stub,
+ UnionMDF(UnionMemberDescriptionFactory { layout: cx.layout_of(union_type), variant, span }),
+ )
+}
+
+//=-----------------------------------------------------------------------------
+// Enums
+//=-----------------------------------------------------------------------------
+
+/// DWARF variant support is only available starting in LLVM 8, but
+/// on MSVC we have to use the fallback mode, because LLVM doesn't
+/// lower variant parts to PDB.
+fn use_enum_fallback(cx: &CodegenCx<'_, '_>) -> bool {
+ cx.sess().target.target.options.is_like_msvc
+}
+
+// FIXME(eddyb) maybe precompute this? Right now it's computed once
+// per generator monomorphization, but it doesn't depend on substs.
+fn generator_layout_and_saved_local_names(
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+) -> (&'tcx GeneratorLayout<'tcx>, IndexVec<mir::GeneratorSavedLocal, Option<Symbol>>) {
+ let body = tcx.optimized_mir(def_id);
+ let generator_layout = body.generator_layout.as_ref().unwrap();
+ let mut generator_saved_local_names = IndexVec::from_elem(None, &generator_layout.field_tys);
+
+ let state_arg = mir::Local::new(1);
+ for var in &body.var_debug_info {
+ if var.place.local != state_arg {
+ continue;
+ }
+ match var.place.projection[..] {
+ [
+ // Deref of the `Pin<&mut Self>` state argument.
+ mir::ProjectionElem::Field(..),
+ mir::ProjectionElem::Deref,
+
+ // Field of a variant of the state.
+ mir::ProjectionElem::Downcast(_, variant),
+ mir::ProjectionElem::Field(field, _),
+ ] => {
+ let name = &mut generator_saved_local_names[
+ generator_layout.variant_fields[variant][field]
+ ];
+ if name.is_none() {
+ name.replace(var.name);
+ }
+ }
+ _ => {}
+ }
+ }
+ (generator_layout, generator_saved_local_names)
+}
+
+/// Describes the members of an enum value; an enum is described as a union of
+/// structs in DWARF. This `MemberDescriptionFactory` provides the description for
+/// the members of this union; so for every variant of the given enum, this
+/// factory will produce one `MemberDescription` (all with no name and a fixed
+/// offset of zero bytes).
+struct EnumMemberDescriptionFactory<'ll, 'tcx> {
+ enum_type: Ty<'tcx>,
+ layout: TyAndLayout<'tcx>,
+ tag_type_metadata: Option<&'ll DIType>,
+ containing_scope: &'ll DIScope,
+ span: Span,
+}
+
+impl EnumMemberDescriptionFactory<'ll, 'tcx> {
+ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> {
+ let generator_variant_info_data = match *self.enum_type.kind() {
+ ty::Generator(def_id, ..) => {
+ Some(generator_layout_and_saved_local_names(cx.tcx, def_id))
+ }
+ _ => None,
+ };
+
+ let variant_info_for = |index: VariantIdx| match *self.enum_type.kind() {
+ ty::Adt(adt, _) => VariantInfo::Adt(&adt.variants[index]),
+ ty::Generator(def_id, _, _) => {
+ let (generator_layout, generator_saved_local_names) =
+ generator_variant_info_data.as_ref().unwrap();
+ VariantInfo::Generator {
+ def_id,
+ generator_layout: *generator_layout,
+ generator_saved_local_names,
+ variant_index: index,
+ }
+ }
+ _ => bug!(),
+ };
+
+ // This will always find the metadata in the type map.
+ let fallback = use_enum_fallback(cx);
+ let self_metadata = if fallback {
+ self.containing_scope
+ } else {
+ type_metadata(cx, self.enum_type, self.span)
+ };
+ let flags = match self.enum_type.kind() {
+ ty::Generator(..) => DIFlags::FlagArtificial,
+ _ => DIFlags::FlagZero,
+ };
+
+ match self.layout.variants {
+ Variants::Single { index } => {
+ if let ty::Adt(adt, _) = self.enum_type.kind() {
+ if adt.variants.is_empty() {
+ return vec![];
+ }
+ }
+
+ let variant_info = variant_info_for(index);
+ let (variant_type_metadata, member_description_factory) = describe_enum_variant(
+ cx,
+ self.layout,
+ variant_info,
+ NoTag,
+ self_metadata,
+ self.span,
+ );
+
+ let member_descriptions = member_description_factory.create_member_descriptions(cx);
+
+ set_members_of_composite_type(
+ cx,
+ self.enum_type,
+ variant_type_metadata,
+ member_descriptions,
+ );
+ vec![MemberDescription {
+ name: if fallback { String::new() } else { variant_info.variant_name() },
+ type_metadata: variant_type_metadata,
+ offset: Size::ZERO,
+ size: self.layout.size,
+ align: self.layout.align.abi,
+ flags,
+ discriminant: None,
+ source_info: variant_info.source_info(cx),
+ }]
+ }
+ Variants::Multiple {
+ tag_encoding: TagEncoding::Direct,
+ tag_field,
+ ref variants,
+ ..
+ } => {
+ let tag_info = if fallback {
+ RegularTag {
+ tag_field: Field::from(tag_field),
+ tag_type_metadata: self.tag_type_metadata.unwrap(),
+ }
+ } else {
+ // This doesn't matter in this case.
+ NoTag
+ };
+ variants
+ .iter_enumerated()
+ .map(|(i, _)| {
+ let variant = self.layout.for_variant(cx, i);
+ let variant_info = variant_info_for(i);
+ let (variant_type_metadata, member_desc_factory) = describe_enum_variant(
+ cx,
+ variant,
+ variant_info,
+ tag_info,
+ self_metadata,
+ self.span,
+ );
+
+ let member_descriptions =
+ member_desc_factory.create_member_descriptions(cx);
+
+ set_members_of_composite_type(
+ cx,
+ self.enum_type,
+ variant_type_metadata,
+ member_descriptions,
+ );
+
+ MemberDescription {
+ name: if fallback {
+ String::new()
+ } else {
+ variant_info.variant_name()
+ },
+ type_metadata: variant_type_metadata,
+ offset: Size::ZERO,
+ size: self.layout.size,
+ align: self.layout.align.abi,
+ flags,
+ discriminant: Some(
+ self.layout.ty.discriminant_for_variant(cx.tcx, i).unwrap().val
+ as u64,
+ ),
+ source_info: variant_info.source_info(cx),
+ }
+ })
+ .collect()
+ }
+ Variants::Multiple {
+ tag_encoding:
+ TagEncoding::Niche { ref niche_variants, niche_start, dataful_variant },
+ ref tag,
+ ref variants,
+ tag_field,
+ } => {
+ if fallback {
+ let variant = self.layout.for_variant(cx, dataful_variant);
+ // Create a description of the non-null variant.
+ let (variant_type_metadata, member_description_factory) = describe_enum_variant(
+ cx,
+ variant,
+ variant_info_for(dataful_variant),
+ OptimizedTag,
+ self.containing_scope,
+ self.span,
+ );
+
+ let variant_member_descriptions =
+ member_description_factory.create_member_descriptions(cx);
+
+ set_members_of_composite_type(
+ cx,
+ self.enum_type,
+ variant_type_metadata,
+ variant_member_descriptions,
+ );
+
+ // Encode the information about the null variant in the union
+ // member's name.
+ let mut name = String::from("RUST$ENCODED$ENUM$");
+ // Right now it's not even going to work for `niche_start > 0`,
+ // and for multiple niche variants it only supports the first.
+ fn compute_field_path<'a, 'tcx>(
+ cx: &CodegenCx<'a, 'tcx>,
+ name: &mut String,
+ layout: TyAndLayout<'tcx>,
+ offset: Size,
+ size: Size,
+ ) {
+ for i in 0..layout.fields.count() {
+ let field_offset = layout.fields.offset(i);
+ if field_offset > offset {
+ continue;
+ }
+ let inner_offset = offset - field_offset;
+ let field = layout.field(cx, i);
+ if inner_offset + size <= field.size {
+ write!(name, "{}$", i).unwrap();
+ compute_field_path(cx, name, field, inner_offset, size);
+ }
+ }
+ }
+ compute_field_path(
+ cx,
+ &mut name,
+ self.layout,
+ self.layout.fields.offset(tag_field),
+ self.layout.field(cx, tag_field).size,
+ );
+ let variant_info = variant_info_for(*niche_variants.start());
+ variant_info.map_struct_name(|variant_name| {
+ name.push_str(variant_name);
+ });
+
+ // Create the (singleton) list of descriptions of union members.
+ vec![MemberDescription {
+ name,
+ type_metadata: variant_type_metadata,
+ offset: Size::ZERO,
+ size: variant.size,
+ align: variant.align.abi,
+ flags,
+ discriminant: None,
+ source_info: variant_info.source_info(cx),
+ }]
+ } else {
+ variants
+ .iter_enumerated()
+ .map(|(i, _)| {
+ let variant = self.layout.for_variant(cx, i);
+ let variant_info = variant_info_for(i);
+ let (variant_type_metadata, member_desc_factory) =
+ describe_enum_variant(
+ cx,
+ variant,
+ variant_info,
+ OptimizedTag,
+ self_metadata,
+ self.span,
+ );
+
+ let member_descriptions =
+ member_desc_factory.create_member_descriptions(cx);
+
+ set_members_of_composite_type(
+ cx,
+ self.enum_type,
+ variant_type_metadata,
+ member_descriptions,
+ );
+
+ let niche_value = if i == dataful_variant {
+ None
+ } else {
+ let value = (i.as_u32() as u128)
+ .wrapping_sub(niche_variants.start().as_u32() as u128)
+ .wrapping_add(niche_start);
+ let value = truncate(value, tag.value.size(cx));
+ // NOTE(eddyb) do *NOT* remove this assert, until
+ // we pass the full 128-bit value to LLVM, otherwise
+ // truncation will be silent and remain undetected.
+ assert_eq!(value as u64 as u128, value);
+ Some(value as u64)
+ };
+
+ MemberDescription {
+ name: variant_info.variant_name(),
+ type_metadata: variant_type_metadata,
+ offset: Size::ZERO,
+ size: self.layout.size,
+ align: self.layout.align.abi,
+ flags,
+ discriminant: niche_value,
+ source_info: variant_info.source_info(cx),
+ }
+ })
+ .collect()
+ }
+ }
+ }
+ }
+}
+
+// Creates `MemberDescription`s for the fields of a single enum variant.
+struct VariantMemberDescriptionFactory<'ll, 'tcx> {
+ /// Cloned from the `layout::Struct` describing the variant.
+ offsets: Vec<Size>,
+ args: Vec<(String, Ty<'tcx>)>,
+ tag_type_metadata: Option<&'ll DIType>,
+ span: Span,
+}
+
+impl VariantMemberDescriptionFactory<'ll, 'tcx> {
+ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> {
+ self.args
+ .iter()
+ .enumerate()
+ .map(|(i, &(ref name, ty))| {
+ // Discriminant is always the first field of our variant
+ // when using the enum fallback.
+ let is_artificial_discr = use_enum_fallback(cx) && i == 0;
+ let (size, align) = cx.size_and_align_of(ty);
+ MemberDescription {
+ name: name.to_string(),
+ type_metadata: if is_artificial_discr {
+ self.tag_type_metadata.unwrap_or_else(|| type_metadata(cx, ty, self.span))
+ } else {
+ type_metadata(cx, ty, self.span)
+ },
+ offset: self.offsets[i],
+ size,
+ align,
+ flags: if is_artificial_discr {
+ DIFlags::FlagArtificial
+ } else {
+ DIFlags::FlagZero
+ },
+ discriminant: None,
+ source_info: None,
+ }
+ })
+ .collect()
+ }
+}
+
+// FIXME: terminology here should be aligned with `abi::TagEncoding`.
+// `OptimizedTag` is `TagEncoding::Niche`, `RegularTag` is `TagEncoding::Direct`.
+// `NoTag` should be removed; users should use `Option<EnumTagInfo>` instead.
+#[derive(Copy, Clone)]
+enum EnumTagInfo<'ll> {
+ RegularTag { tag_field: Field, tag_type_metadata: &'ll DIType },
+ OptimizedTag,
+ NoTag,
+}
+
+#[derive(Copy, Clone)]
+enum VariantInfo<'a, 'tcx> {
+ Adt(&'tcx ty::VariantDef),
+ Generator {
+ def_id: DefId,
+ generator_layout: &'tcx GeneratorLayout<'tcx>,
+ generator_saved_local_names: &'a IndexVec<mir::GeneratorSavedLocal, Option<Symbol>>,
+ variant_index: VariantIdx,
+ },
+}
+
+impl<'tcx> VariantInfo<'_, 'tcx> {
+ fn map_struct_name<R>(&self, f: impl FnOnce(&str) -> R) -> R {
+ match self {
+ VariantInfo::Adt(variant) => f(&variant.ident.as_str()),
+ VariantInfo::Generator { variant_index, .. } => {
+ f(&GeneratorSubsts::variant_name(*variant_index))
+ }
+ }
+ }
+
+ fn variant_name(&self) -> String {
+ match self {
+ VariantInfo::Adt(variant) => variant.ident.to_string(),
+ VariantInfo::Generator { variant_index, .. } => {
+ // Since GDB currently prints out the raw discriminant along
+ // with every variant, make each variant name be just the value
+ // of the discriminant. The struct name for the variant includes
+ // the actual variant description.
+ format!("{}", variant_index.as_usize())
+ }
+ }
+ }
+
+ fn field_name(&self, i: usize) -> String {
+ let field_name = match *self {
+ VariantInfo::Adt(variant) if variant.ctor_kind != CtorKind::Fn => {
+ Some(variant.fields[i].ident.name)
+ }
+ VariantInfo::Generator {
+ generator_layout,
+ generator_saved_local_names,
+ variant_index,
+ ..
+ } => {
+ generator_saved_local_names
+ [generator_layout.variant_fields[variant_index][i.into()]]
+ }
+ _ => None,
+ };
+ field_name.map(|name| name.to_string()).unwrap_or_else(|| format!("__{}", i))
+ }
+
+ fn source_info(&self, cx: &CodegenCx<'ll, 'tcx>) -> Option<SourceInfo<'ll>> {
+ match self {
+ VariantInfo::Generator { def_id, variant_index, .. } => {
+ let span =
+ cx.tcx.generator_layout(*def_id).variant_source_info[*variant_index].span;
+ if !span.is_dummy() {
+ let loc = cx.lookup_debug_loc(span.lo());
+ return Some(SourceInfo {
+ file: file_metadata(cx, &loc.file, def_id.krate),
+ line: loc.line.unwrap_or(UNKNOWN_LINE_NUMBER),
+ });
+ }
+ }
+ _ => {}
+ }
+ None
+ }
+
+ fn is_artificial(&self) -> bool {
+ match self {
+ VariantInfo::Generator { .. } => true,
+ VariantInfo::Adt(..) => false,
+ }
+ }
+}
+
+/// Returns a tuple of (1) `type_metadata_stub` of the variant, (2) a
+/// `MemberDescriptionFactory` for producing the descriptions of the
+/// fields of the variant. This is a rudimentary version of a full
+/// `RecursiveTypeDescription`.
+fn describe_enum_variant(
+ cx: &CodegenCx<'ll, 'tcx>,
+ layout: layout::TyAndLayout<'tcx>,
+ variant: VariantInfo<'_, 'tcx>,
+ discriminant_info: EnumTagInfo<'ll>,
+ containing_scope: &'ll DIScope,
+ span: Span,
+) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) {
+ let metadata_stub = variant.map_struct_name(|variant_name| {
+ let unique_type_id = debug_context(cx)
+ .type_map
+ .borrow_mut()
+ .get_unique_type_id_of_enum_variant(cx, layout.ty, &variant_name);
+ create_struct_stub(
+ cx,
+ layout.ty,
+ &variant_name,
+ unique_type_id,
+ Some(containing_scope),
+ // FIXME(tmandry): This doesn't seem to have any effect.
+ if variant.is_artificial() { DIFlags::FlagArtificial } else { DIFlags::FlagZero },
+ )
+ });
+
+ // Build an array of (field name, field type) pairs to be captured in the factory closure.
+ let (offsets, args) = if use_enum_fallback(cx) {
+ // If this is not a univariant enum, there is also the discriminant field.
+ let (discr_offset, discr_arg) = match discriminant_info {
+ RegularTag { tag_field, .. } => {
+ // We have the layout of an enum variant, we need the layout of the outer enum
+ let enum_layout = cx.layout_of(layout.ty);
+ let offset = enum_layout.fields.offset(tag_field.as_usize());
+ let args =
+ ("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty);
+ (Some(offset), Some(args))
+ }
+ _ => (None, None),
+ };
+ (
+ discr_offset
+ .into_iter()
+ .chain((0..layout.fields.count()).map(|i| layout.fields.offset(i)))
+ .collect(),
+ discr_arg
+ .into_iter()
+ .chain(
+ (0..layout.fields.count())
+ .map(|i| (variant.field_name(i), layout.field(cx, i).ty)),
+ )
+ .collect(),
+ )
+ } else {
+ (
+ (0..layout.fields.count()).map(|i| layout.fields.offset(i)).collect(),
+ (0..layout.fields.count())
+ .map(|i| (variant.field_name(i), layout.field(cx, i).ty))
+ .collect(),
+ )
+ };
+
+ let member_description_factory = VariantMDF(VariantMemberDescriptionFactory {
+ offsets,
+ args,
+ tag_type_metadata: match discriminant_info {
+ RegularTag { tag_type_metadata, .. } => Some(tag_type_metadata),
+ _ => None,
+ },
+ span,
+ });
+
+ (metadata_stub, member_description_factory)
+}
+
+fn prepare_enum_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ enum_type: Ty<'tcx>,
+ enum_def_id: DefId,
+ unique_type_id: UniqueTypeId,
+ span: Span,
+ outer_field_tys: Vec<Ty<'tcx>>,
+) -> RecursiveTypeDescription<'ll, 'tcx> {
+ let tcx = cx.tcx;
+ let enum_name = compute_debuginfo_type_name(tcx, enum_type, false);
+ // FIXME(tmandry): This doesn't seem to have any effect.
+ let enum_flags = match enum_type.kind() {
+ ty::Generator(..) => DIFlags::FlagArtificial,
+ _ => DIFlags::FlagZero,
+ };
+
+ let containing_scope = get_namespace_for_item(cx, enum_def_id);
+ // FIXME: This should emit actual file metadata for the enum, but we
+ // currently can't get the necessary information when it comes to types
+ // imported from other crates. Formerly we violated the ODR when performing
+ // LTO because we emitted debuginfo for the same type with varying file
+ // metadata, so as a workaround we pretend that the type comes from
+ // <unknown>
+ let file_metadata = unknown_file_metadata(cx);
+
+ let discriminant_type_metadata = |discr: Primitive| {
+ let enumerators_metadata: Vec<_> = match enum_type.kind() {
+ ty::Adt(def, _) => def
+ .discriminants(tcx)
+ .zip(&def.variants)
+ .map(|((_, discr), v)| {
+ let name = v.ident.as_str();
+ let is_unsigned = match discr.ty.kind() {
+ ty::Int(_) => false,
+ ty::Uint(_) => true,
+ _ => bug!("non integer discriminant"),
+ };
+ unsafe {
+ Some(llvm::LLVMRustDIBuilderCreateEnumerator(
+ DIB(cx),
+ name.as_ptr().cast(),
+ name.len(),
+ // FIXME: what if enumeration has i128 discriminant?
+ discr.val as i64,
+ is_unsigned,
+ ))
+ }
+ })
+ .collect(),
+ ty::Generator(_, substs, _) => substs
+ .as_generator()
+ .variant_range(enum_def_id, tcx)
+ .map(|variant_index| {
+ debug_assert_eq!(tcx.types.u32, substs.as_generator().discr_ty(tcx));
+ let name = GeneratorSubsts::variant_name(variant_index);
+ unsafe {
+ Some(llvm::LLVMRustDIBuilderCreateEnumerator(
+ DIB(cx),
+ name.as_ptr().cast(),
+ name.len(),
+ // Generators use u32 as discriminant type, verified above.
+ variant_index.as_u32().into(),
+ true, // IsUnsigned
+ ))
+ }
+ })
+ .collect(),
+ _ => bug!(),
+ };
+
+ let disr_type_key = (enum_def_id, discr);
+ let cached_discriminant_type_metadata =
+ debug_context(cx).created_enum_disr_types.borrow().get(&disr_type_key).cloned();
+ match cached_discriminant_type_metadata {
+ Some(discriminant_type_metadata) => discriminant_type_metadata,
+ None => {
+ let (discriminant_size, discriminant_align) = (discr.size(cx), discr.align(cx));
+ let discriminant_base_type_metadata =
+ type_metadata(cx, discr.to_ty(tcx), rustc_span::DUMMY_SP);
+
+ let item_name;
+ let discriminant_name = match enum_type.kind() {
+ ty::Adt(..) => {
+ item_name = tcx.item_name(enum_def_id).as_str();
+ &*item_name
+ }
+ ty::Generator(..) => enum_name.as_str(),
+ _ => bug!(),
+ };
+
+ let discriminant_type_metadata = unsafe {
+ llvm::LLVMRustDIBuilderCreateEnumerationType(
+ DIB(cx),
+ containing_scope,
+ discriminant_name.as_ptr().cast(),
+ discriminant_name.len(),
+ file_metadata,
+ UNKNOWN_LINE_NUMBER,
+ discriminant_size.bits(),
+ discriminant_align.abi.bits() as u32,
+ create_DIArray(DIB(cx), &enumerators_metadata),
+ discriminant_base_type_metadata,
+ true,
+ )
+ };
+
+ debug_context(cx)
+ .created_enum_disr_types
+ .borrow_mut()
+ .insert(disr_type_key, discriminant_type_metadata);
+
+ discriminant_type_metadata
+ }
+ }
+ };
+
+ let layout = cx.layout_of(enum_type);
+
+ if let (
+ &Abi::Scalar(_),
+ &Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. },
+ ) = (&layout.abi, &layout.variants)
+ {
+ return FinalMetadata(discriminant_type_metadata(tag.value));
+ }
+
+ if use_enum_fallback(cx) {
+ let discriminant_type_metadata = match layout.variants {
+ Variants::Single { .. }
+ | Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => None,
+ Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => {
+ Some(discriminant_type_metadata(tag.value))
+ }
+ };
+
+ let enum_metadata = {
+ let type_map = debug_context(cx).type_map.borrow();
+ let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id);
+
+ unsafe {
+ llvm::LLVMRustDIBuilderCreateUnionType(
+ DIB(cx),
+ containing_scope,
+ enum_name.as_ptr().cast(),
+ enum_name.len(),
+ file_metadata,
+ UNKNOWN_LINE_NUMBER,
+ layout.size.bits(),
+ layout.align.abi.bits() as u32,
+ enum_flags,
+ None,
+ 0, // RuntimeLang
+ unique_type_id_str.as_ptr().cast(),
+ unique_type_id_str.len(),
+ )
+ }
+ };
+
+ return create_and_register_recursive_type_forward_declaration(
+ cx,
+ enum_type,
+ unique_type_id,
+ enum_metadata,
+ enum_metadata,
+ EnumMDF(EnumMemberDescriptionFactory {
+ enum_type,
+ layout,
+ tag_type_metadata: discriminant_type_metadata,
+ containing_scope,
+ span,
+ }),
+ );
+ }
+
+ let discriminator_name = match enum_type.kind() {
+ ty::Generator(..) => "__state",
+ _ => "",
+ };
+ let discriminator_metadata = match layout.variants {
+ // A single-variant enum has no discriminant.
+ Variants::Single { .. } => None,
+
+ Variants::Multiple {
+ tag_encoding: TagEncoding::Niche { .. }, ref tag, tag_field, ..
+ } => {
+ // Find the integer type of the correct size.
+ let size = tag.value.size(cx);
+ let align = tag.value.align(cx);
+
+ let tag_type = match tag.value {
+ Int(t, _) => t,
+ F32 => Integer::I32,
+ F64 => Integer::I64,
+ Pointer => cx.data_layout().ptr_sized_integer(),
+ }
+ .to_ty(cx.tcx, false);
+
+ let tag_metadata = basic_type_metadata(cx, tag_type);
+ unsafe {
+ Some(llvm::LLVMRustDIBuilderCreateMemberType(
+ DIB(cx),
+ containing_scope,
+ discriminator_name.as_ptr().cast(),
+ discriminator_name.len(),
+ file_metadata,
+ UNKNOWN_LINE_NUMBER,
+ size.bits(),
+ align.abi.bits() as u32,
+ layout.fields.offset(tag_field).bits(),
+ DIFlags::FlagArtificial,
+ tag_metadata,
+ ))
+ }
+ }
+
+ Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, tag_field, .. } => {
+ let discr_type = tag.value.to_ty(cx.tcx);
+ let (size, align) = cx.size_and_align_of(discr_type);
+
+ let discr_metadata = basic_type_metadata(cx, discr_type);
+ unsafe {
+ Some(llvm::LLVMRustDIBuilderCreateMemberType(
+ DIB(cx),
+ containing_scope,
+ discriminator_name.as_ptr().cast(),
+ discriminator_name.len(),
+ file_metadata,
+ UNKNOWN_LINE_NUMBER,
+ size.bits(),
+ align.bits() as u32,
+ layout.fields.offset(tag_field).bits(),
+ DIFlags::FlagArtificial,
+ discr_metadata,
+ ))
+ }
+ }
+ };
+
+ let mut outer_fields = match layout.variants {
+ Variants::Single { .. } => vec![],
+ Variants::Multiple { .. } => {
+ let tuple_mdf = TupleMemberDescriptionFactory {
+ ty: enum_type,
+ component_types: outer_field_tys,
+ span,
+ };
+ tuple_mdf
+ .create_member_descriptions(cx)
+ .into_iter()
+ .map(|desc| Some(desc.into_metadata(cx, containing_scope)))
+ .collect()
+ }
+ };
+
+ let variant_part_unique_type_id_str = debug_context(cx)
+ .type_map
+ .borrow_mut()
+ .get_unique_type_id_str_of_enum_variant_part(unique_type_id);
+ let empty_array = create_DIArray(DIB(cx), &[]);
+ let name = "";
+ let variant_part = unsafe {
+ llvm::LLVMRustDIBuilderCreateVariantPart(
+ DIB(cx),
+ containing_scope,
+ name.as_ptr().cast(),
+ name.len(),
+ file_metadata,
+ UNKNOWN_LINE_NUMBER,
+ layout.size.bits(),
+ layout.align.abi.bits() as u32,
+ enum_flags,
+ discriminator_metadata,
+ empty_array,
+ variant_part_unique_type_id_str.as_ptr().cast(),
+ variant_part_unique_type_id_str.len(),
+ )
+ };
+ outer_fields.push(Some(variant_part));
+
+ let struct_wrapper = {
+ // The variant part must be wrapped in a struct according to DWARF.
+ let type_array = create_DIArray(DIB(cx), &outer_fields);
+
+ let type_map = debug_context(cx).type_map.borrow();
+ let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id);
+
+ unsafe {
+ llvm::LLVMRustDIBuilderCreateStructType(
+ DIB(cx),
+ Some(containing_scope),
+ enum_name.as_ptr().cast(),
+ enum_name.len(),
+ file_metadata,
+ UNKNOWN_LINE_NUMBER,
+ layout.size.bits(),
+ layout.align.abi.bits() as u32,
+ enum_flags,
+ None,
+ type_array,
+ 0,
+ None,
+ unique_type_id_str.as_ptr().cast(),
+ unique_type_id_str.len(),
+ )
+ }
+ };
+
+ create_and_register_recursive_type_forward_declaration(
+ cx,
+ enum_type,
+ unique_type_id,
+ struct_wrapper,
+ variant_part,
+ EnumMDF(EnumMemberDescriptionFactory {
+ enum_type,
+ layout,
+ tag_type_metadata: None,
+ containing_scope,
+ span,
+ }),
+ )
+}
+
+/// Creates debug information for a composite type, that is, anything that
+/// results in a LLVM struct.
+///
+/// Examples of Rust types to use this are: structs, tuples, boxes, vecs, and enums.
+fn composite_type_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ composite_type: Ty<'tcx>,
+ composite_type_name: &str,
+ composite_type_unique_id: UniqueTypeId,
+ member_descriptions: Vec<MemberDescription<'ll>>,
+ containing_scope: Option<&'ll DIScope>,
+
+ // Ignore source location information as long as it
+ // can't be reconstructed for non-local crates.
+ _file_metadata: &'ll DIFile,
+ _definition_span: Span,
+) -> &'ll DICompositeType {
+ // Create the (empty) struct metadata node ...
+ let composite_type_metadata = create_struct_stub(
+ cx,
+ composite_type,
+ composite_type_name,
+ composite_type_unique_id,
+ containing_scope,
+ DIFlags::FlagZero,
+ );
+ // ... and immediately create and add the member descriptions.
+ set_members_of_composite_type(cx, composite_type, composite_type_metadata, member_descriptions);
+
+ composite_type_metadata
+}
+
+fn set_members_of_composite_type(
+ cx: &CodegenCx<'ll, 'tcx>,
+ composite_type: Ty<'tcx>,
+ composite_type_metadata: &'ll DICompositeType,
+ member_descriptions: Vec<MemberDescription<'ll>>,
+) {
+ // In some rare cases LLVM metadata uniquing would lead to an existing type
+ // description being used instead of a new one created in
+ // create_struct_stub. This would cause a hard to trace assertion in
+ // DICompositeType::SetTypeArray(). The following check makes sure that we
+ // get a better error message if this should happen again due to some
+ // regression.
+ {
+ let mut composite_types_completed =
+ debug_context(cx).composite_types_completed.borrow_mut();
+ if !composite_types_completed.insert(&composite_type_metadata) {
+ bug!(
+ "debuginfo::set_members_of_composite_type() - \
+ Already completed forward declaration re-encountered."
+ );
+ }
+ }
+
+ let member_metadata: Vec<_> = member_descriptions
+ .into_iter()
+ .map(|desc| Some(desc.into_metadata(cx, composite_type_metadata)))
+ .collect();
+
+ let type_params = compute_type_parameters(cx, composite_type);
+ unsafe {
+ let type_array = create_DIArray(DIB(cx), &member_metadata[..]);
+ llvm::LLVMRustDICompositeTypeReplaceArrays(
+ DIB(cx),
+ composite_type_metadata,
+ Some(type_array),
+ type_params,
+ );
+ }
+}
+
+/// Computes the type parameters for a type, if any, for the given metadata.
+fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> Option<&'ll DIArray> {
+ if let ty::Adt(def, substs) = *ty.kind() {
+ if substs.types().next().is_some() {
+ let generics = cx.tcx.generics_of(def.did);
+ let names = get_parameter_names(cx, generics);
+ let template_params: Vec<_> = substs
+ .iter()
+ .zip(names)
+ .filter_map(|(kind, name)| {
+ if let GenericArgKind::Type(ty) = kind.unpack() {
+ let actual_type =
+ cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
+ let actual_type_metadata =
+ type_metadata(cx, actual_type, rustc_span::DUMMY_SP);
+ let name = &name.as_str();
+ Some(unsafe {
+ Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
+ DIB(cx),
+ None,
+ name.as_ptr().cast(),
+ name.len(),
+ actual_type_metadata,
+ ))
+ })
+ } else {
+ None
+ }
+ })
+ .collect();
+
+ return Some(create_DIArray(DIB(cx), &template_params[..]));
+ }
+ }
+ return Some(create_DIArray(DIB(cx), &[]));
+
+ fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
+ let mut names = generics
+ .parent
+ .map_or(vec![], |def_id| get_parameter_names(cx, cx.tcx.generics_of(def_id)));
+ names.extend(generics.params.iter().map(|param| param.name));
+ names
+ }
+}
+
+/// A convenience wrapper around `LLVMRustDIBuilderCreateStructType()`. Does not do
+/// any caching, does not add any fields to the struct. This can be done later
+/// with `set_members_of_composite_type()`.
+fn create_struct_stub(
+ cx: &CodegenCx<'ll, 'tcx>,
+ struct_type: Ty<'tcx>,
+ struct_type_name: &str,
+ unique_type_id: UniqueTypeId,
+ containing_scope: Option<&'ll DIScope>,
+ flags: DIFlags,
+) -> &'ll DICompositeType {
+ let (struct_size, struct_align) = cx.size_and_align_of(struct_type);
+
+ let type_map = debug_context(cx).type_map.borrow();
+ let unique_type_id = type_map.get_unique_type_id_as_string(unique_type_id);
+
+ let metadata_stub = unsafe {
+ // `LLVMRustDIBuilderCreateStructType()` wants an empty array. A null
+ // pointer will lead to hard to trace and debug LLVM assertions
+ // later on in `llvm/lib/IR/Value.cpp`.
+ let empty_array = create_DIArray(DIB(cx), &[]);
+
+ llvm::LLVMRustDIBuilderCreateStructType(
+ DIB(cx),
+ containing_scope,
+ struct_type_name.as_ptr().cast(),
+ struct_type_name.len(),
+ unknown_file_metadata(cx),
+ UNKNOWN_LINE_NUMBER,
+ struct_size.bits(),
+ struct_align.bits() as u32,
+ flags,
+ None,
+ empty_array,
+ 0,
+ None,
+ unique_type_id.as_ptr().cast(),
+ unique_type_id.len(),
+ )
+ };
+
+ metadata_stub
+}
+
+fn create_union_stub(
+ cx: &CodegenCx<'ll, 'tcx>,
+ union_type: Ty<'tcx>,
+ union_type_name: &str,
+ unique_type_id: UniqueTypeId,
+ containing_scope: &'ll DIScope,
+) -> &'ll DICompositeType {
+ let (union_size, union_align) = cx.size_and_align_of(union_type);
+
+ let type_map = debug_context(cx).type_map.borrow();
+ let unique_type_id = type_map.get_unique_type_id_as_string(unique_type_id);
+
+ let metadata_stub = unsafe {
+ // `LLVMRustDIBuilderCreateUnionType()` wants an empty array. A null
+ // pointer will lead to hard to trace and debug LLVM assertions
+ // later on in `llvm/lib/IR/Value.cpp`.
+ let empty_array = create_DIArray(DIB(cx), &[]);
+
+ llvm::LLVMRustDIBuilderCreateUnionType(
+ DIB(cx),
+ containing_scope,
+ union_type_name.as_ptr().cast(),
+ union_type_name.len(),
+ unknown_file_metadata(cx),
+ UNKNOWN_LINE_NUMBER,
+ union_size.bits(),
+ union_align.bits() as u32,
+ DIFlags::FlagZero,
+ Some(empty_array),
+ 0, // RuntimeLang
+ unique_type_id.as_ptr().cast(),
+ unique_type_id.len(),
+ )
+ };
+
+ metadata_stub
+}
+
+/// Creates debug information for the given global variable.
+///
+/// Adds the created metadata nodes directly to the crate's IR.
+pub fn create_global_var_metadata(cx: &CodegenCx<'ll, '_>, def_id: DefId, global: &'ll Value) {
+ if cx.dbg_cx.is_none() {
+ return;
+ }
+
+ // Only create type information if full debuginfo is enabled
+ if cx.sess().opts.debuginfo != DebugInfo::Full {
+ return;
+ }
+
+ let tcx = cx.tcx;
+
+ // We may want to remove the namespace scope if we're in an extern block (see
+ // https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952).
+ let var_scope = get_namespace_for_item(cx, def_id);
+ let span = tcx.def_span(def_id);
+
+ let (file_metadata, line_number) = if !span.is_dummy() {
+ let loc = cx.lookup_debug_loc(span.lo());
+ (file_metadata(cx, &loc.file, LOCAL_CRATE), loc.line)
+ } else {
+ (unknown_file_metadata(cx), None)
+ };
+
+ let is_local_to_unit = is_node_local_to_unit(cx, def_id);
+ let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx, ty::ParamEnv::reveal_all());
+ let type_metadata = type_metadata(cx, variable_type, span);
+ let var_name = tcx.item_name(def_id).as_str();
+ let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name;
+ // When empty, linkage_name field is omitted,
+ // which is what we want for no_mangle statics
+ let linkage_name = if var_name == linkage_name { "" } else { linkage_name };
+
+ let global_align = cx.align_of(variable_type);
+
+ unsafe {
+ llvm::LLVMRustDIBuilderCreateStaticVariable(
+ DIB(cx),
+ Some(var_scope),
+ var_name.as_ptr().cast(),
+ var_name.len(),
+ linkage_name.as_ptr().cast(),
+ linkage_name.len(),
+ file_metadata,
+ line_number.unwrap_or(UNKNOWN_LINE_NUMBER),
+ type_metadata,
+ is_local_to_unit,
+ global,
+ None,
+ global_align.bytes() as u32,
+ );
+ }
+}
+
+/// Creates debug information for the given vtable, which is for the
+/// given type.
+///
+/// Adds the created metadata nodes directly to the crate's IR.
+pub fn create_vtable_metadata(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, vtable: &'ll Value) {
+ if cx.dbg_cx.is_none() {
+ return;
+ }
+
+ // Only create type information if full debuginfo is enabled
+ if cx.sess().opts.debuginfo != DebugInfo::Full {
+ return;
+ }
+
+ let type_metadata = type_metadata(cx, ty, rustc_span::DUMMY_SP);
+
+ unsafe {
+ // `LLVMRustDIBuilderCreateStructType()` wants an empty array. A null
+ // pointer will lead to hard to trace and debug LLVM assertions
+ // later on in `llvm/lib/IR/Value.cpp`.
+ let empty_array = create_DIArray(DIB(cx), &[]);
+ let name = "vtable";
+
+ // Create a new one each time. We don't want metadata caching
+ // here, because each vtable will refer to a unique containing
+ // type.
+ let vtable_type = llvm::LLVMRustDIBuilderCreateStructType(
+ DIB(cx),
+ NO_SCOPE_METADATA,
+ name.as_ptr().cast(),
+ name.len(),
+ unknown_file_metadata(cx),
+ UNKNOWN_LINE_NUMBER,
+ Size::ZERO.bits(),
+ cx.tcx.data_layout.pointer_align.abi.bits() as u32,
+ DIFlags::FlagArtificial,
+ None,
+ empty_array,
+ 0,
+ Some(type_metadata),
+ name.as_ptr().cast(),
+ name.len(),
+ );
+
+ let linkage_name = "";
+ llvm::LLVMRustDIBuilderCreateStaticVariable(
+ DIB(cx),
+ NO_SCOPE_METADATA,
+ name.as_ptr().cast(),
+ name.len(),
+ linkage_name.as_ptr().cast(),
+ linkage_name.len(),
+ unknown_file_metadata(cx),
+ UNKNOWN_LINE_NUMBER,
+ vtable_type,
+ true,
+ vtable,
+ None,
+ 0,
+ );
+ }
+}
+
+/// Creates an "extension" of an existing `DIScope` into another file.
+pub fn extend_scope_to_file(
+ cx: &CodegenCx<'ll, '_>,
+ scope_metadata: &'ll DIScope,
+ file: &rustc_span::SourceFile,
+ defining_crate: CrateNum,
+) -> &'ll DILexicalBlock {
+ let file_metadata = file_metadata(cx, &file, defining_crate);
+ unsafe { llvm::LLVMRustDIBuilderCreateLexicalBlockFile(DIB(cx), scope_metadata, file_metadata) }
+}
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
new file mode 100644
index 0000000..7cdd366
--- /dev/null
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -0,0 +1,563 @@
+// See doc.rs for documentation.
+mod doc;
+
+use rustc_codegen_ssa::mir::debuginfo::VariableKind::*;
+
+use self::metadata::{file_metadata, type_metadata, TypeMap, UNKNOWN_LINE_NUMBER};
+use self::namespace::mangled_name_of_instance;
+use self::type_names::compute_debuginfo_type_name;
+use self::utils::{create_DIArray, is_node_local_to_unit, DIB};
+
+use crate::abi::FnAbi;
+use crate::builder::Builder;
+use crate::common::CodegenCx;
+use crate::llvm;
+use crate::llvm::debuginfo::{
+ DIArray, DIBuilder, DIFile, DIFlags, DILexicalBlock, DISPFlags, DIScope, DIType, DIVariable,
+};
+use crate::value::Value;
+
+use rustc_codegen_ssa::debuginfo::type_names;
+use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind};
+use rustc_codegen_ssa::traits::*;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
+use rustc_index::vec::IndexVec;
+use rustc_middle::mir;
+use rustc_middle::ty::layout::HasTyCtxt;
+use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
+use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TypeFoldable};
+use rustc_session::config::{self, DebugInfo};
+use rustc_span::symbol::Symbol;
+use rustc_span::{self, BytePos, Span};
+use rustc_target::abi::{LayoutOf, Primitive, Size};
+
+use libc::c_uint;
+use smallvec::SmallVec;
+use std::cell::RefCell;
+use tracing::debug;
+
+mod create_scope_map;
+pub mod gdb;
+pub mod metadata;
+mod namespace;
+mod source_loc;
+mod utils;
+
+pub use self::create_scope_map::compute_mir_scopes;
+pub use self::metadata::create_global_var_metadata;
+pub use self::metadata::extend_scope_to_file;
+
+#[allow(non_upper_case_globals)]
+const DW_TAG_auto_variable: c_uint = 0x100;
+#[allow(non_upper_case_globals)]
+const DW_TAG_arg_variable: c_uint = 0x101;
+
+/// A context object for maintaining all state needed by the debuginfo module.
+pub struct CrateDebugContext<'a, 'tcx> {
+ llcontext: &'a llvm::Context,
+ llmod: &'a llvm::Module,
+ builder: &'a mut DIBuilder<'a>,
+ created_files: RefCell<FxHashMap<(Option<String>, Option<String>), &'a DIFile>>,
+ created_enum_disr_types: RefCell<FxHashMap<(DefId, Primitive), &'a DIType>>,
+
+ type_map: RefCell<TypeMap<'a, 'tcx>>,
+ namespace_map: RefCell<DefIdMap<&'a DIScope>>,
+
+ // This collection is used to assert that composite types (structs, enums,
+ // ...) have their members only set once:
+ composite_types_completed: RefCell<FxHashSet<&'a DIType>>,
+}
+
+impl Drop for CrateDebugContext<'a, 'tcx> {
+ fn drop(&mut self) {
+ unsafe {
+ llvm::LLVMRustDIBuilderDispose(&mut *(self.builder as *mut _));
+ }
+ }
+}
+
+impl<'a, 'tcx> CrateDebugContext<'a, 'tcx> {
+ pub fn new(llmod: &'a llvm::Module) -> Self {
+ debug!("CrateDebugContext::new");
+ let builder = unsafe { llvm::LLVMRustDIBuilderCreate(llmod) };
+ // DIBuilder inherits context from the module, so we'd better use the same one
+ let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) };
+ CrateDebugContext {
+ llcontext,
+ llmod,
+ builder,
+ created_files: Default::default(),
+ created_enum_disr_types: Default::default(),
+ type_map: Default::default(),
+ namespace_map: RefCell::new(Default::default()),
+ composite_types_completed: Default::default(),
+ }
+ }
+}
+
+/// Creates any deferred debug metadata nodes
+pub fn finalize(cx: &CodegenCx<'_, '_>) {
+ if cx.dbg_cx.is_none() {
+ return;
+ }
+
+ debug!("finalize");
+
+ if gdb::needs_gdb_debug_scripts_section(cx) {
+ // Add a .debug_gdb_scripts section to this compile-unit. This will
+ // cause GDB to try and load the gdb_load_rust_pretty_printers.py file,
+ // which activates the Rust pretty printers for binary this section is
+ // contained in.
+ gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
+ }
+
+ unsafe {
+ llvm::LLVMRustDIBuilderFinalize(DIB(cx));
+ // Debuginfo generation in LLVM by default uses a higher
+ // version of dwarf than macOS currently understands. We can
+ // instruct LLVM to emit an older version of dwarf, however,
+ // for macOS to understand. For more info see #11352
+ // This can be overridden using --llvm-opts -dwarf-version,N.
+ // Android has the same issue (#22398)
+ if cx.sess().target.target.options.is_like_osx
+ || cx.sess().target.target.options.is_like_android
+ {
+ llvm::LLVMRustAddModuleFlag(cx.llmod, "Dwarf Version\0".as_ptr().cast(), 2)
+ }
+
+ // Indicate that we want CodeView debug information on MSVC
+ if cx.sess().target.target.options.is_like_msvc {
+ llvm::LLVMRustAddModuleFlag(cx.llmod, "CodeView\0".as_ptr().cast(), 1)
+ }
+
+ // Prevent bitcode readers from deleting the debug info.
+ let ptr = "Debug Info Version\0".as_ptr();
+ llvm::LLVMRustAddModuleFlag(cx.llmod, ptr.cast(), llvm::LLVMRustDebugMetadataVersion());
+ };
+}
+
+impl DebugInfoBuilderMethods for Builder<'a, 'll, 'tcx> {
+ // FIXME(eddyb) find a common convention for all of the debuginfo-related
+ // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
+ fn dbg_var_addr(
+ &mut self,
+ dbg_var: &'ll DIVariable,
+ scope_metadata: &'ll DIScope,
+ variable_alloca: Self::Value,
+ direct_offset: Size,
+ indirect_offsets: &[Size],
+ span: Span,
+ ) {
+ let cx = self.cx();
+
+ // Convert the direct and indirect offsets to address ops.
+ // FIXME(eddyb) use `const`s instead of getting the values via FFI,
+ // the values should match the ones in the DWARF standard anyway.
+ let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() };
+ let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() };
+ let mut addr_ops = SmallVec::<[_; 8]>::new();
+
+ if direct_offset.bytes() > 0 {
+ addr_ops.push(op_plus_uconst());
+ addr_ops.push(direct_offset.bytes() as i64);
+ }
+ for &offset in indirect_offsets {
+ addr_ops.push(op_deref());
+ if offset.bytes() > 0 {
+ addr_ops.push(op_plus_uconst());
+ addr_ops.push(offset.bytes() as i64);
+ }
+ }
+
+ // FIXME(eddyb) maybe this information could be extracted from `dbg_var`,
+ // to avoid having to pass it down in both places?
+ // NB: `var` doesn't seem to know about the column, so that's a limitation.
+ let dbg_loc = cx.create_debug_loc(scope_metadata, span);
+ unsafe {
+ // FIXME(eddyb) replace `llvm.dbg.declare` with `llvm.dbg.addr`.
+ llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
+ DIB(cx),
+ variable_alloca,
+ dbg_var,
+ addr_ops.as_ptr(),
+ addr_ops.len() as c_uint,
+ dbg_loc,
+ self.llbb(),
+ );
+ }
+ }
+
+ fn set_source_location(&mut self, scope: &'ll DIScope, span: Span) {
+ debug!("set_source_location: {}", self.sess().source_map().span_to_string(span));
+
+ let dbg_loc = self.cx().create_debug_loc(scope, span);
+
+ unsafe {
+ llvm::LLVMSetCurrentDebugLocation(self.llbuilder, dbg_loc);
+ }
+ }
+ fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
+ gdb::insert_reference_to_gdb_debug_scripts_section_global(self)
+ }
+
+ fn set_var_name(&mut self, value: &'ll Value, name: &str) {
+ // Avoid wasting time if LLVM value names aren't even enabled.
+ if self.sess().fewer_names() {
+ return;
+ }
+
+ // Only function parameters and instructions are local to a function,
+ // don't change the name of anything else (e.g. globals).
+ let param_or_inst = unsafe {
+ llvm::LLVMIsAArgument(value).is_some() || llvm::LLVMIsAInstruction(value).is_some()
+ };
+ if !param_or_inst {
+ return;
+ }
+
+ // Avoid replacing the name if it already exists.
+ // While we could combine the names somehow, it'd
+ // get noisy quick, and the usefulness is dubious.
+ if llvm::get_value_name(value).is_empty() {
+ llvm::set_value_name(value, name.as_bytes());
+ }
+ }
+}
+
+impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
+ fn create_function_debug_context(
+ &self,
+ instance: Instance<'tcx>,
+ fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+ llfn: &'ll Value,
+ mir: &mir::Body<'_>,
+ ) -> Option<FunctionDebugContext<&'ll DIScope>> {
+ if self.sess().opts.debuginfo == DebugInfo::None {
+ return None;
+ }
+
+ let span = mir.span;
+
+ // This can be the case for functions inlined from another crate
+ if span.is_dummy() {
+ // FIXME(simulacrum): Probably can't happen; remove.
+ return None;
+ }
+
+ let def_id = instance.def_id();
+ let containing_scope = get_containing_scope(self, instance);
+ let loc = self.lookup_debug_loc(span.lo());
+ let file_metadata = file_metadata(self, &loc.file, def_id.krate);
+
+ let function_type_metadata = unsafe {
+ let fn_signature = get_function_signature(self, fn_abi);
+ llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(self), fn_signature)
+ };
+
+ // Find the enclosing function, in case this is a closure.
+ let def_key = self.tcx().def_key(def_id);
+ let mut name = def_key.disambiguated_data.data.to_string();
+
+ let enclosing_fn_def_id = self.tcx().closure_base_def_id(def_id);
+
+ // Get_template_parameters() will append a `<...>` clause to the function
+ // name if necessary.
+ let generics = self.tcx().generics_of(enclosing_fn_def_id);
+ let substs = instance.substs.truncate_to(self.tcx(), generics);
+ let template_parameters = get_template_parameters(self, &generics, substs, &mut name);
+
+ let linkage_name = &mangled_name_of_instance(self, instance).name;
+ // Omit the linkage_name if it is the same as subprogram name.
+ let linkage_name = if &name == linkage_name { "" } else { linkage_name };
+
+ // FIXME(eddyb) does this need to be separate from `loc.line` for some reason?
+ let scope_line = loc.line;
+
+ let mut flags = DIFlags::FlagPrototyped;
+
+ if fn_abi.ret.layout.abi.is_uninhabited() {
+ flags |= DIFlags::FlagNoReturn;
+ }
+
+ let mut spflags = DISPFlags::SPFlagDefinition;
+ if is_node_local_to_unit(self, def_id) {
+ spflags |= DISPFlags::SPFlagLocalToUnit;
+ }
+ if self.sess().opts.optimize != config::OptLevel::No {
+ spflags |= DISPFlags::SPFlagOptimized;
+ }
+ if let Some((id, _)) = self.tcx.entry_fn(LOCAL_CRATE) {
+ if id.to_def_id() == def_id {
+ spflags |= DISPFlags::SPFlagMainSubprogram;
+ }
+ }
+
+ let fn_metadata = unsafe {
+ llvm::LLVMRustDIBuilderCreateFunction(
+ DIB(self),
+ containing_scope,
+ name.as_ptr().cast(),
+ name.len(),
+ linkage_name.as_ptr().cast(),
+ linkage_name.len(),
+ file_metadata,
+ loc.line.unwrap_or(UNKNOWN_LINE_NUMBER),
+ function_type_metadata,
+ scope_line.unwrap_or(UNKNOWN_LINE_NUMBER),
+ flags,
+ spflags,
+ llfn,
+ template_parameters,
+ None,
+ )
+ };
+
+ // Initialize fn debug context (including scopes).
+ // FIXME(eddyb) figure out a way to not need `Option` for `scope_metadata`.
+ let null_scope = DebugScope {
+ scope_metadata: None,
+ file_start_pos: BytePos(0),
+ file_end_pos: BytePos(0),
+ };
+ let mut fn_debug_context = FunctionDebugContext {
+ scopes: IndexVec::from_elem(null_scope, &mir.source_scopes),
+ defining_crate: def_id.krate,
+ };
+
+ // Fill in all the scopes, with the information from the MIR body.
+ compute_mir_scopes(self, mir, fn_metadata, &mut fn_debug_context);
+
+ return Some(fn_debug_context);
+
+ fn get_function_signature<'ll, 'tcx>(
+ cx: &CodegenCx<'ll, 'tcx>,
+ fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+ ) -> &'ll DIArray {
+ if cx.sess().opts.debuginfo == DebugInfo::Limited {
+ return create_DIArray(DIB(cx), &[]);
+ }
+
+ let mut signature = Vec::with_capacity(fn_abi.args.len() + 1);
+
+ // Return type -- llvm::DIBuilder wants this at index 0
+ signature.push(if fn_abi.ret.is_ignore() {
+ None
+ } else {
+ Some(type_metadata(cx, fn_abi.ret.layout.ty, rustc_span::DUMMY_SP))
+ });
+
+ // Arguments types
+ if cx.sess().target.target.options.is_like_msvc {
+ // FIXME(#42800):
+ // There is a bug in MSDIA that leads to a crash when it encounters
+ // a fixed-size array of `u8` or something zero-sized in a
+ // function-type (see #40477).
+ // As a workaround, we replace those fixed-size arrays with a
+ // pointer-type. So a function `fn foo(a: u8, b: [u8; 4])` would
+ // appear as `fn foo(a: u8, b: *const u8)` in debuginfo,
+ // and a function `fn bar(x: [(); 7])` as `fn bar(x: *const ())`.
+ // This transformed type is wrong, but these function types are
+ // already inaccurate due to ABI adjustments (see #42800).
+ signature.extend(fn_abi.args.iter().map(|arg| {
+ let t = arg.layout.ty;
+ let t = match t.kind() {
+ ty::Array(ct, _)
+ if (*ct == cx.tcx.types.u8) || cx.layout_of(ct).is_zst() =>
+ {
+ cx.tcx.mk_imm_ptr(ct)
+ }
+ _ => t,
+ };
+ Some(type_metadata(cx, t, rustc_span::DUMMY_SP))
+ }));
+ } else {
+ signature.extend(
+ fn_abi
+ .args
+ .iter()
+ .map(|arg| Some(type_metadata(cx, arg.layout.ty, rustc_span::DUMMY_SP))),
+ );
+ }
+
+ create_DIArray(DIB(cx), &signature[..])
+ }
+
+ fn get_template_parameters<'ll, 'tcx>(
+ cx: &CodegenCx<'ll, 'tcx>,
+ generics: &ty::Generics,
+ substs: SubstsRef<'tcx>,
+ name_to_append_suffix_to: &mut String,
+ ) -> &'ll DIArray {
+ if substs.types().next().is_none() {
+ return create_DIArray(DIB(cx), &[]);
+ }
+
+ name_to_append_suffix_to.push('<');
+ for (i, actual_type) in substs.types().enumerate() {
+ if i != 0 {
+ name_to_append_suffix_to.push_str(",");
+ }
+
+ let actual_type =
+ cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), actual_type);
+ // Add actual type name to <...> clause of function name
+ let actual_type_name = compute_debuginfo_type_name(cx.tcx(), actual_type, true);
+ name_to_append_suffix_to.push_str(&actual_type_name[..]);
+ }
+ name_to_append_suffix_to.push('>');
+
+ // Again, only create type information if full debuginfo is enabled
+ let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full {
+ let names = get_parameter_names(cx, generics);
+ substs
+ .iter()
+ .zip(names)
+ .filter_map(|(kind, name)| {
+ if let GenericArgKind::Type(ty) = kind.unpack() {
+ let actual_type =
+ cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
+ let actual_type_metadata =
+ type_metadata(cx, actual_type, rustc_span::DUMMY_SP);
+ let name = name.as_str();
+ Some(unsafe {
+ Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
+ DIB(cx),
+ None,
+ name.as_ptr().cast(),
+ name.len(),
+ actual_type_metadata,
+ ))
+ })
+ } else {
+ None
+ }
+ })
+ .collect()
+ } else {
+ vec![]
+ };
+
+ create_DIArray(DIB(cx), &template_params[..])
+ }
+
+ fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
+ let mut names = generics
+ .parent
+ .map_or(vec![], |def_id| get_parameter_names(cx, cx.tcx.generics_of(def_id)));
+ names.extend(generics.params.iter().map(|param| param.name));
+ names
+ }
+
+ fn get_containing_scope<'ll, 'tcx>(
+ cx: &CodegenCx<'ll, 'tcx>,
+ instance: Instance<'tcx>,
+ ) -> &'ll DIScope {
+ // First, let's see if this is a method within an inherent impl. Because
+ // if yes, we want to make the result subroutine DIE a child of the
+ // subroutine's self-type.
+ let self_type = cx.tcx.impl_of_method(instance.def_id()).and_then(|impl_def_id| {
+ // If the method does *not* belong to a trait, proceed
+ if cx.tcx.trait_id_of_impl(impl_def_id).is_none() {
+ let impl_self_ty = cx.tcx.subst_and_normalize_erasing_regions(
+ instance.substs,
+ ty::ParamEnv::reveal_all(),
+ &cx.tcx.type_of(impl_def_id),
+ );
+
+ // Only "class" methods are generally understood by LLVM,
+ // so avoid methods on other types (e.g., `<*mut T>::null`).
+ match impl_self_ty.kind() {
+ ty::Adt(def, ..) if !def.is_box() => {
+ // Again, only create type information if full debuginfo is enabled
+ if cx.sess().opts.debuginfo == DebugInfo::Full
+ && !impl_self_ty.needs_subst()
+ {
+ Some(type_metadata(cx, impl_self_ty, rustc_span::DUMMY_SP))
+ } else {
+ Some(namespace::item_namespace(cx, def.did))
+ }
+ }
+ _ => None,
+ }
+ } else {
+ // For trait method impls we still use the "parallel namespace"
+ // strategy
+ None
+ }
+ });
+
+ self_type.unwrap_or_else(|| {
+ namespace::item_namespace(
+ cx,
+ DefId {
+ krate: instance.def_id().krate,
+ index: cx
+ .tcx
+ .def_key(instance.def_id())
+ .parent
+ .expect("get_containing_scope: missing parent?"),
+ },
+ )
+ })
+ }
+ }
+
+ fn create_vtable_metadata(&self, ty: Ty<'tcx>, vtable: Self::Value) {
+ metadata::create_vtable_metadata(self, ty, vtable)
+ }
+
+ fn extend_scope_to_file(
+ &self,
+ scope_metadata: &'ll DIScope,
+ file: &rustc_span::SourceFile,
+ defining_crate: CrateNum,
+ ) -> &'ll DILexicalBlock {
+ metadata::extend_scope_to_file(&self, scope_metadata, file, defining_crate)
+ }
+
+ fn debuginfo_finalize(&self) {
+ finalize(self)
+ }
+
+ // FIXME(eddyb) find a common convention for all of the debuginfo-related
+ // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
+ fn create_dbg_var(
+ &self,
+ dbg_context: &FunctionDebugContext<&'ll DIScope>,
+ variable_name: Symbol,
+ variable_type: Ty<'tcx>,
+ scope_metadata: &'ll DIScope,
+ variable_kind: VariableKind,
+ span: Span,
+ ) -> &'ll DIVariable {
+ let loc = self.lookup_debug_loc(span.lo());
+ let file_metadata = file_metadata(self, &loc.file, dbg_context.defining_crate);
+
+ let type_metadata = type_metadata(self, variable_type, span);
+
+ let (argument_index, dwarf_tag) = match variable_kind {
+ ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable),
+ LocalVariable => (0, DW_TAG_auto_variable),
+ };
+ let align = self.align_of(variable_type);
+
+ let name = variable_name.as_str();
+ unsafe {
+ llvm::LLVMRustDIBuilderCreateVariable(
+ DIB(self),
+ dwarf_tag,
+ scope_metadata,
+ name.as_ptr().cast(),
+ name.len(),
+ file_metadata,
+ loc.line.unwrap_or(UNKNOWN_LINE_NUMBER),
+ type_metadata,
+ true,
+ DIFlags::FlagZero,
+ argument_index,
+ align.bytes() as u32,
+ )
+ }
+ }
+}
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs
new file mode 100644
index 0000000..9945d4f
--- /dev/null
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs
@@ -0,0 +1,55 @@
+// Namespace Handling.
+
+use super::utils::{debug_context, DIB};
+use rustc_middle::ty::{self, Instance};
+
+use crate::common::CodegenCx;
+use crate::llvm;
+use crate::llvm::debuginfo::DIScope;
+use rustc_hir::def_id::DefId;
+use rustc_hir::definitions::DefPathData;
+
+pub fn mangled_name_of_instance<'a, 'tcx>(
+ cx: &CodegenCx<'a, 'tcx>,
+ instance: Instance<'tcx>,
+) -> ty::SymbolName<'tcx> {
+ let tcx = cx.tcx;
+ tcx.symbol_name(instance)
+}
+
+pub fn item_namespace(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
+ if let Some(&scope) = debug_context(cx).namespace_map.borrow().get(&def_id) {
+ return scope;
+ }
+
+ let def_key = cx.tcx.def_key(def_id);
+ let parent_scope = def_key
+ .parent
+ .map(|parent| item_namespace(cx, DefId { krate: def_id.krate, index: parent }));
+
+ let crate_name_as_str;
+ let name_to_string;
+ let namespace_name = match def_key.disambiguated_data.data {
+ DefPathData::CrateRoot => {
+ crate_name_as_str = cx.tcx.crate_name(def_id.krate).as_str();
+ &*crate_name_as_str
+ }
+ data => {
+ name_to_string = data.to_string();
+ &*name_to_string
+ }
+ };
+
+ let scope = unsafe {
+ llvm::LLVMRustDIBuilderCreateNameSpace(
+ DIB(cx),
+ parent_scope,
+ namespace_name.as_ptr().cast(),
+ namespace_name.len(),
+ false, // ExportSymbols (only relevant for C++ anonymous namespaces)
+ )
+ };
+
+ debug_context(cx).namespace_map.borrow_mut().insert(def_id, scope);
+ scope
+}
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs b/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs
new file mode 100644
index 0000000..66ae9d7
--- /dev/null
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs
@@ -0,0 +1,61 @@
+use super::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER};
+use super::utils::debug_context;
+
+use crate::common::CodegenCx;
+use crate::llvm::debuginfo::DIScope;
+use crate::llvm::{self, Value};
+use rustc_codegen_ssa::traits::*;
+
+use rustc_data_structures::sync::Lrc;
+use rustc_span::{BytePos, Pos, SourceFile, SourceFileAndLine, Span};
+
+/// A source code location used to generate debug information.
+pub struct DebugLoc {
+ /// Information about the original source file.
+ pub file: Lrc<SourceFile>,
+ /// The (1-based) line number.
+ pub line: Option<u32>,
+ /// The (1-based) column number.
+ pub col: Option<u32>,
+}
+
+impl CodegenCx<'ll, '_> {
+ /// Looks up debug source information about a `BytePos`.
+ pub fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
+ let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
+ Ok(SourceFileAndLine { sf: file, line }) => {
+ let line_pos = file.line_begin_pos(pos);
+
+ // Use 1-based indexing.
+ let line = (line + 1) as u32;
+ let col = (pos - line_pos).to_u32() + 1;
+
+ (file, Some(line), Some(col))
+ }
+ Err(file) => (file, None, None),
+ };
+
+ // For MSVC, omit the column number.
+ // Otherwise, emit it. This mimics clang behaviour.
+ // See discussion in https://github.com/rust-lang/rust/issues/42921
+ if self.sess().target.target.options.is_like_msvc {
+ DebugLoc { file, line, col: None }
+ } else {
+ DebugLoc { file, line, col }
+ }
+ }
+
+ pub fn create_debug_loc(&self, scope: &'ll DIScope, span: Span) -> &'ll Value {
+ let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo());
+
+ unsafe {
+ llvm::LLVMRustDIBuilderCreateDebugLocation(
+ debug_context(self).llcontext,
+ line.unwrap_or(UNKNOWN_LINE_NUMBER),
+ col.unwrap_or(UNKNOWN_COLUMN_NUMBER),
+ scope,
+ None,
+ )
+ }
+ }
+}
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
new file mode 100644
index 0000000..ee188e6
--- /dev/null
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
@@ -0,0 +1,43 @@
+// Utility Functions.
+
+use super::namespace::item_namespace;
+use super::CrateDebugContext;
+
+use rustc_hir::def_id::DefId;
+use rustc_middle::ty::DefIdTree;
+
+use crate::common::CodegenCx;
+use crate::llvm;
+use crate::llvm::debuginfo::{DIArray, DIBuilder, DIDescriptor, DIScope};
+
+pub fn is_node_local_to_unit(cx: &CodegenCx<'_, '_>, def_id: DefId) -> bool {
+ // The is_local_to_unit flag indicates whether a function is local to the
+ // current compilation unit (i.e., if it is *static* in the C-sense). The
+ // *reachable* set should provide a good approximation of this, as it
+ // contains everything that might leak out of the current crate (by being
+ // externally visible or by being inlined into something externally
+ // visible). It might better to use the `exported_items` set from
+ // `driver::CrateAnalysis` in the future, but (atm) this set is not
+ // available in the codegen pass.
+ !cx.tcx.is_reachable_non_generic(def_id)
+}
+
+#[allow(non_snake_case)]
+pub fn create_DIArray(builder: &DIBuilder<'ll>, arr: &[Option<&'ll DIDescriptor>]) -> &'ll DIArray {
+ unsafe { llvm::LLVMRustDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len() as u32) }
+}
+
+#[inline]
+pub fn debug_context(cx: &'a CodegenCx<'ll, 'tcx>) -> &'a CrateDebugContext<'ll, 'tcx> {
+ cx.dbg_cx.as_ref().unwrap()
+}
+
+#[inline]
+#[allow(non_snake_case)]
+pub fn DIB(cx: &'a CodegenCx<'ll, '_>) -> &'a DIBuilder<'ll> {
+ cx.dbg_cx.as_ref().unwrap().builder
+}
+
+pub fn get_namespace_for_item(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
+ item_namespace(cx, cx.tcx.parent(def_id).expect("get_namespace_for_item: missing parent?"))
+}