// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use self::InternalDebugLocation::*; use super::utils::{debug_context, span_start}; use super::metadata::UNKNOWN_COLUMN_NUMBER; use super::FunctionDebugContext; use llvm; use llvm::debuginfo::DIScope; use builder::Builder; use libc::c_uint; use syntax_pos::{Span, Pos}; /// Sets the current debug location at the beginning of the span. /// /// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...). pub fn set_source_location( debug_context: &FunctionDebugContext<'ll>, bx: &Builder<'_, 'll, '_>, scope: Option<&'ll DIScope>, span: Span, ) { let function_debug_context = match *debug_context { FunctionDebugContext::DebugInfoDisabled => return, FunctionDebugContext::FunctionWithoutDebugInfo => { set_debug_location(bx, UnknownLocation); return; } FunctionDebugContext::RegularContext(ref data) => data }; let dbg_loc = if function_debug_context.source_locations_enabled.get() { debug!("set_source_location: {}", bx.sess().source_map().span_to_string(span)); let loc = span_start(bx.cx, span); InternalDebugLocation::new(scope.unwrap(), loc.line, loc.col.to_usize()) } else { UnknownLocation }; set_debug_location(bx, dbg_loc); } /// Enables emitting source locations for the given functions. /// /// Since we don't want source locations to be emitted for the function prelude, /// they are disabled when beginning to codegen a new function. This functions /// switches source location emitting on and must therefore be called before the /// first real statement/expression of the function is codegened. pub fn start_emitting_source_locations(dbg_context: &FunctionDebugContext<'ll>) { if let FunctionDebugContext::RegularContext(ref data) = *dbg_context { data.source_locations_enabled.set(true); } } #[derive(Copy, Clone, PartialEq)] pub enum InternalDebugLocation<'ll> { KnownLocation { scope: &'ll DIScope, line: usize, col: usize }, UnknownLocation } impl InternalDebugLocation<'ll> { pub fn new(scope: &'ll DIScope, line: usize, col: usize) -> Self { KnownLocation { scope, line, col, } } } pub fn set_debug_location(bx: &Builder<'_, 'll, '_>, debug_location: InternalDebugLocation<'ll>) { let metadata_node = match debug_location { KnownLocation { scope, line, col } => { // For MSVC, set the column number to zero. // Otherwise, emit it. This mimics clang behaviour. // See discussion in https://github.com/rust-lang/rust/issues/42921 let col_used = if bx.cx.sess().target.target.options.is_like_msvc { UNKNOWN_COLUMN_NUMBER } else { col as c_uint }; debug!("setting debug location to {} {}", line, col); unsafe { Some(llvm::LLVMRustDIBuilderCreateDebugLocation( debug_context(bx.cx).llcontext, line as c_uint, col_used, scope, None)) } } UnknownLocation => { debug!("clearing debug location "); None } }; unsafe { llvm::LLVMSetCurrentDebugLocation(bx.llbuilder, metadata_node); } }