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, }; }