mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-04 19:29:07 +00:00
Translate inline assembly errors back to source locations
Fixes #17552.
This commit is contained in:
parent
34dfa45718
commit
9d60de93e2
@ -16,6 +16,7 @@ use driver::session::Session;
|
|||||||
use driver::config;
|
use driver::config;
|
||||||
use llvm;
|
use llvm;
|
||||||
use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef, ContextRef};
|
use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef, ContextRef};
|
||||||
|
use llvm::SMDiagnosticRef;
|
||||||
use util::common::time;
|
use util::common::time;
|
||||||
use syntax::abi;
|
use syntax::abi;
|
||||||
use syntax::codemap;
|
use syntax::codemap;
|
||||||
@ -326,14 +327,40 @@ impl<'a> CodegenContext<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DiagHandlerFreeVars<'a> {
|
struct HandlerFreeVars<'a> {
|
||||||
llcx: ContextRef,
|
llcx: ContextRef,
|
||||||
cgcx: &'a CodegenContext<'a>,
|
cgcx: &'a CodegenContext<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn inline_asm_handler(diag: SMDiagnosticRef,
|
||||||
|
user: *const c_void,
|
||||||
|
cookie: c_uint) {
|
||||||
|
use syntax::codemap::ExpnId;
|
||||||
|
|
||||||
|
let HandlerFreeVars { cgcx, .. }
|
||||||
|
= *mem::transmute::<_, *const HandlerFreeVars>(user);
|
||||||
|
|
||||||
|
let msg = llvm::build_string(|s| llvm::LLVMWriteSMDiagnosticToString(diag, s))
|
||||||
|
.expect("non-UTF8 SMDiagnostic");
|
||||||
|
|
||||||
|
match cgcx.lto_ctxt {
|
||||||
|
Some((sess, _)) => {
|
||||||
|
sess.codemap().with_expn_info(ExpnId(cookie as u32), |info| match info {
|
||||||
|
Some(ei) => sess.span_err(ei.call_site, msg.as_slice()),
|
||||||
|
None => sess.err(msg.as_slice()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
None => {
|
||||||
|
cgcx.handler.err(msg.as_slice());
|
||||||
|
cgcx.handler.note("build without -C codegen-units for more exact errors");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_void) {
|
unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_void) {
|
||||||
let DiagHandlerFreeVars { llcx, cgcx }
|
let HandlerFreeVars { llcx, cgcx }
|
||||||
= *mem::transmute::<_, *const DiagHandlerFreeVars>(user);
|
= *mem::transmute::<_, *const HandlerFreeVars>(user);
|
||||||
|
|
||||||
match llvm::diagnostic::Diagnostic::unpack(info) {
|
match llvm::diagnostic::Diagnostic::unpack(info) {
|
||||||
llvm::diagnostic::Optimization(opt) => {
|
llvm::diagnostic::Optimization(opt) => {
|
||||||
@ -368,14 +395,16 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
|
|||||||
let tm = config.tm;
|
let tm = config.tm;
|
||||||
|
|
||||||
// llcx doesn't outlive this function, so we can put this on the stack.
|
// llcx doesn't outlive this function, so we can put this on the stack.
|
||||||
let fv = DiagHandlerFreeVars {
|
let fv = HandlerFreeVars {
|
||||||
llcx: llcx,
|
llcx: llcx,
|
||||||
cgcx: cgcx,
|
cgcx: cgcx,
|
||||||
};
|
};
|
||||||
|
let fv = &fv as *const HandlerFreeVars as *mut c_void;
|
||||||
|
|
||||||
|
llvm::LLVMSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, fv);
|
||||||
|
|
||||||
if !cgcx.remark.is_empty() {
|
if !cgcx.remark.is_empty() {
|
||||||
llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler,
|
llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, fv);
|
||||||
&fv as *const DiagHandlerFreeVars
|
|
||||||
as *mut c_void);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.emit_no_opt_bc {
|
if config.emit_no_opt_bc {
|
||||||
|
@ -556,6 +556,8 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
|
|||||||
sess.opts.output_types.as_slice(),
|
sess.opts.output_types.as_slice(),
|
||||||
outputs));
|
outputs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sess.abort_if_errors();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the linker on any artifacts that resulted from the LLVM run.
|
/// Run the linker on any artifacts that resulted from the LLVM run.
|
||||||
|
@ -25,6 +25,7 @@ use middle::trans::type_::Type;
|
|||||||
use std::c_str::ToCStr;
|
use std::c_str::ToCStr;
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
use libc::{c_uint, c_char};
|
||||||
|
|
||||||
// Take an inline assembly expression and splat it out via LLVM
|
// Take an inline assembly expression and splat it out via LLVM
|
||||||
pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
|
pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
|
||||||
@ -141,6 +142,19 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store expn_id in a metadata node so we can map LLVM errors
|
||||||
|
// back to source locations. See #17552.
|
||||||
|
unsafe {
|
||||||
|
let key = "srcloc";
|
||||||
|
let kind = llvm::LLVMGetMDKindIDInContext(bcx.ccx().llcx(),
|
||||||
|
key.as_ptr() as *const c_char, key.len() as c_uint);
|
||||||
|
|
||||||
|
let val: llvm::ValueRef = C_i32(bcx.ccx(), ia.expn_id as i32);
|
||||||
|
|
||||||
|
llvm::LLVMSetMetadata(r, kind,
|
||||||
|
llvm::LLVMMDNodeInContext(bcx.ccx().llcx(), &val, 1));
|
||||||
|
}
|
||||||
|
|
||||||
return bcx;
|
return bcx;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -424,8 +424,11 @@ pub enum DiagnosticInfo_opaque {}
|
|||||||
pub type DiagnosticInfoRef = *mut DiagnosticInfo_opaque;
|
pub type DiagnosticInfoRef = *mut DiagnosticInfo_opaque;
|
||||||
pub enum DebugLoc_opaque {}
|
pub enum DebugLoc_opaque {}
|
||||||
pub type DebugLocRef = *mut DebugLoc_opaque;
|
pub type DebugLocRef = *mut DebugLoc_opaque;
|
||||||
|
pub enum SMDiagnostic_opaque {}
|
||||||
|
pub type SMDiagnosticRef = *mut SMDiagnostic_opaque;
|
||||||
|
|
||||||
pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void);
|
pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void);
|
||||||
|
pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint);
|
||||||
|
|
||||||
pub mod debuginfo {
|
pub mod debuginfo {
|
||||||
use super::{ValueRef};
|
use super::{ValueRef};
|
||||||
@ -1967,6 +1970,12 @@ extern {
|
|||||||
pub fn LLVMGetDiagInfoKind(DI: DiagnosticInfoRef) -> DiagnosticKind;
|
pub fn LLVMGetDiagInfoKind(DI: DiagnosticInfoRef) -> DiagnosticKind;
|
||||||
|
|
||||||
pub fn LLVMWriteDebugLocToString(C: ContextRef, DL: DebugLocRef, s: RustStringRef);
|
pub fn LLVMWriteDebugLocToString(C: ContextRef, DL: DebugLocRef, s: RustStringRef);
|
||||||
|
|
||||||
|
pub fn LLVMSetInlineAsmDiagnosticHandler(C: ContextRef,
|
||||||
|
H: InlineAsmDiagHandler,
|
||||||
|
CX: *mut c_void);
|
||||||
|
|
||||||
|
pub fn LLVMWriteSMDiagnosticToString(d: SMDiagnosticRef, s: RustStringRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn SetInstructionCallConv(instr: ValueRef, cc: CallConv) {
|
pub fn SetInstructionCallConv(instr: ValueRef, cc: CallConv) {
|
||||||
|
@ -983,7 +983,8 @@ pub struct InlineAsm {
|
|||||||
pub clobbers: InternedString,
|
pub clobbers: InternedString,
|
||||||
pub volatile: bool,
|
pub volatile: bool,
|
||||||
pub alignstack: bool,
|
pub alignstack: bool,
|
||||||
pub dialect: AsmDialect
|
pub dialect: AsmDialect,
|
||||||
|
pub expn_id: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// represents an argument in a function header
|
/// represents an argument in a function header
|
||||||
|
@ -224,7 +224,7 @@ pub struct ExpnInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(PartialEq, Eq, Clone, Show, Hash)]
|
#[deriving(PartialEq, Eq, Clone, Show, Hash)]
|
||||||
pub struct ExpnId(u32);
|
pub struct ExpnId(pub u32);
|
||||||
|
|
||||||
pub static NO_EXPANSION: ExpnId = ExpnId(-1);
|
pub static NO_EXPANSION: ExpnId = ExpnId(-1);
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use ast;
|
use ast;
|
||||||
|
use codemap;
|
||||||
use codemap::Span;
|
use codemap::Span;
|
||||||
use ext::base;
|
use ext::base;
|
||||||
use ext::base::*;
|
use ext::base::*;
|
||||||
@ -198,6 +199,15 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let codemap::ExpnId(expn_id) = cx.codemap().record_expansion(codemap::ExpnInfo {
|
||||||
|
call_site: sp,
|
||||||
|
callee: codemap::NameAndSpan {
|
||||||
|
name: "asm".to_string(),
|
||||||
|
format: codemap::MacroBang,
|
||||||
|
span: None,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
MacExpr::new(P(ast::Expr {
|
MacExpr::new(P(ast::Expr {
|
||||||
id: ast::DUMMY_NODE_ID,
|
id: ast::DUMMY_NODE_ID,
|
||||||
node: ast::ExprInlineAsm(ast::InlineAsm {
|
node: ast::ExprInlineAsm(ast::InlineAsm {
|
||||||
@ -208,7 +218,8 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
|
|||||||
clobbers: token::intern_and_get_ident(cons.as_slice()),
|
clobbers: token::intern_and_get_ident(cons.as_slice()),
|
||||||
volatile: volatile,
|
volatile: volatile,
|
||||||
alignstack: alignstack,
|
alignstack: alignstack,
|
||||||
dialect: dialect
|
dialect: dialect,
|
||||||
|
expn_id: expn_id,
|
||||||
}),
|
}),
|
||||||
span: sp
|
span: sp
|
||||||
}))
|
}))
|
||||||
|
@ -1279,7 +1279,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
|
|||||||
clobbers,
|
clobbers,
|
||||||
volatile,
|
volatile,
|
||||||
alignstack,
|
alignstack,
|
||||||
dialect
|
dialect,
|
||||||
|
expn_id,
|
||||||
}) => ExprInlineAsm(InlineAsm {
|
}) => ExprInlineAsm(InlineAsm {
|
||||||
inputs: inputs.move_map(|(c, input)| {
|
inputs: inputs.move_map(|(c, input)| {
|
||||||
(c, folder.fold_expr(input))
|
(c, folder.fold_expr(input))
|
||||||
@ -1292,7 +1293,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
|
|||||||
clobbers: clobbers,
|
clobbers: clobbers,
|
||||||
volatile: volatile,
|
volatile: volatile,
|
||||||
alignstack: alignstack,
|
alignstack: alignstack,
|
||||||
dialect: dialect
|
dialect: dialect,
|
||||||
|
expn_id: expn_id,
|
||||||
}),
|
}),
|
||||||
ExprMac(mac) => ExprMac(folder.fold_mac(mac)),
|
ExprMac(mac) => ExprMac(folder.fold_mac(mac)),
|
||||||
ExprStruct(path, fields, maybe_expr) => {
|
ExprStruct(path, fields, maybe_expr) => {
|
||||||
|
@ -871,3 +871,18 @@ extern "C" void LLVMWriteDebugLocToString(
|
|||||||
raw_rust_string_ostream os(str);
|
raw_rust_string_ostream os(str);
|
||||||
unwrap(dl)->print(*unwrap(C), os);
|
unwrap(dl)->print(*unwrap(C), os);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef)
|
||||||
|
|
||||||
|
extern "C" void LLVMSetInlineAsmDiagnosticHandler(
|
||||||
|
LLVMContextRef C,
|
||||||
|
LLVMContext::InlineAsmDiagHandlerTy H,
|
||||||
|
void *CX)
|
||||||
|
{
|
||||||
|
unwrap(C)->setInlineAsmDiagnosticHandler(H, CX);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void LLVMWriteSMDiagnosticToString(LLVMSMDiagnosticRef d, RustStringRef str) {
|
||||||
|
raw_rust_string_ostream os(str);
|
||||||
|
unwrap(d)->print("", os);
|
||||||
|
}
|
||||||
|
@ -73,6 +73,7 @@ void LLVMRustSetLastError(const char*);
|
|||||||
typedef struct OpaqueRustString *RustStringRef;
|
typedef struct OpaqueRustString *RustStringRef;
|
||||||
typedef struct LLVMOpaqueTwine *LLVMTwineRef;
|
typedef struct LLVMOpaqueTwine *LLVMTwineRef;
|
||||||
typedef struct LLVMOpaqueDebugLoc *LLVMDebugLocRef;
|
typedef struct LLVMOpaqueDebugLoc *LLVMDebugLocRef;
|
||||||
|
typedef struct LLVMOpaqueSMDiagnostic *LLVMSMDiagnosticRef;
|
||||||
|
|
||||||
extern "C" void
|
extern "C" void
|
||||||
rust_llvm_string_write_impl(RustStringRef str, const char *ptr, size_t size);
|
rust_llvm_string_write_impl(RustStringRef str, const char *ptr, size_t size);
|
||||||
|
20
src/test/compile-fail/asm-src-loc-codegen-units.rs
Normal file
20
src/test/compile-fail/asm-src-loc-codegen-units.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// Copyright 2014 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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
//
|
||||||
|
// compile-flags: -C codegen-units=2
|
||||||
|
// error-pattern: build without -C codegen-units for more exact errors
|
||||||
|
|
||||||
|
#![feature(asm)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
unsafe {
|
||||||
|
asm!("nowayisthisavalidinstruction");
|
||||||
|
}
|
||||||
|
}
|
17
src/test/compile-fail/asm-src-loc.rs
Normal file
17
src/test/compile-fail/asm-src-loc.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2014 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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(asm)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
unsafe {
|
||||||
|
asm!("nowayisthisavalidinstruction"); //~ ERROR invalid instruction mnemonic
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user