Skip to content

Commit 9d60de9

Browse files
committed
Translate inline assembly errors back to source locations
Fixes rust-lang#17552.
1 parent 34dfa45 commit 9d60de9

File tree

12 files changed

+133
-12
lines changed

12 files changed

+133
-12
lines changed

src/librustc/back/write.rs

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use driver::session::Session;
1616
use driver::config;
1717
use llvm;
1818
use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef, ContextRef};
19+
use llvm::SMDiagnosticRef;
1920
use util::common::time;
2021
use syntax::abi;
2122
use syntax::codemap;
@@ -326,14 +327,40 @@ impl<'a> CodegenContext<'a> {
326327
}
327328
}
328329

329-
struct DiagHandlerFreeVars<'a> {
330+
struct HandlerFreeVars<'a> {
330331
llcx: ContextRef,
331332
cgcx: &'a CodegenContext<'a>,
332333
}
333334

335+
unsafe extern "C" fn inline_asm_handler(diag: SMDiagnosticRef,
336+
user: *const c_void,
337+
cookie: c_uint) {
338+
use syntax::codemap::ExpnId;
339+
340+
let HandlerFreeVars { cgcx, .. }
341+
= *mem::transmute::<_, *const HandlerFreeVars>(user);
342+
343+
let msg = llvm::build_string(|s| llvm::LLVMWriteSMDiagnosticToString(diag, s))
344+
.expect("non-UTF8 SMDiagnostic");
345+
346+
match cgcx.lto_ctxt {
347+
Some((sess, _)) => {
348+
sess.codemap().with_expn_info(ExpnId(cookie as u32), |info| match info {
349+
Some(ei) => sess.span_err(ei.call_site, msg.as_slice()),
350+
None => sess.err(msg.as_slice()),
351+
});
352+
}
353+
354+
None => {
355+
cgcx.handler.err(msg.as_slice());
356+
cgcx.handler.note("build without -C codegen-units for more exact errors");
357+
}
358+
}
359+
}
360+
334361
unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_void) {
335-
let DiagHandlerFreeVars { llcx, cgcx }
336-
= *mem::transmute::<_, *const DiagHandlerFreeVars>(user);
362+
let HandlerFreeVars { llcx, cgcx }
363+
= *mem::transmute::<_, *const HandlerFreeVars>(user);
337364

338365
match llvm::diagnostic::Diagnostic::unpack(info) {
339366
llvm::diagnostic::Optimization(opt) => {
@@ -368,14 +395,16 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
368395
let tm = config.tm;
369396

370397
// llcx doesn't outlive this function, so we can put this on the stack.
371-
let fv = DiagHandlerFreeVars {
398+
let fv = HandlerFreeVars {
372399
llcx: llcx,
373400
cgcx: cgcx,
374401
};
402+
let fv = &fv as *const HandlerFreeVars as *mut c_void;
403+
404+
llvm::LLVMSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, fv);
405+
375406
if !cgcx.remark.is_empty() {
376-
llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler,
377-
&fv as *const DiagHandlerFreeVars
378-
as *mut c_void);
407+
llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, fv);
379408
}
380409

381410
if config.emit_no_opt_bc {

src/librustc/driver/driver.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,8 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
556556
sess.opts.output_types.as_slice(),
557557
outputs));
558558
}
559+
560+
sess.abort_if_errors();
559561
}
560562

561563
/// Run the linker on any artifacts that resulted from the LLVM run.

src/librustc/middle/trans/asm.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use middle::trans::type_::Type;
2525
use std::c_str::ToCStr;
2626
use std::string::String;
2727
use syntax::ast;
28+
use libc::{c_uint, c_char};
2829

2930
// Take an inline assembly expression and splat it out via LLVM
3031
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)
141142
}
142143
}
143144

145+
// Store expn_id in a metadata node so we can map LLVM errors
146+
// back to source locations. See #17552.
147+
unsafe {
148+
let key = "srcloc";
149+
let kind = llvm::LLVMGetMDKindIDInContext(bcx.ccx().llcx(),
150+
key.as_ptr() as *const c_char, key.len() as c_uint);
151+
152+
let val: llvm::ValueRef = C_i32(bcx.ccx(), ia.expn_id as i32);
153+
154+
llvm::LLVMSetMetadata(r, kind,
155+
llvm::LLVMMDNodeInContext(bcx.ccx().llcx(), &val, 1));
156+
}
157+
144158
return bcx;
145159

146160
}

src/librustc_llvm/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,8 +424,11 @@ pub enum DiagnosticInfo_opaque {}
424424
pub type DiagnosticInfoRef = *mut DiagnosticInfo_opaque;
425425
pub enum DebugLoc_opaque {}
426426
pub type DebugLocRef = *mut DebugLoc_opaque;
427+
pub enum SMDiagnostic_opaque {}
428+
pub type SMDiagnosticRef = *mut SMDiagnostic_opaque;
427429

428430
pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void);
431+
pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint);
429432

430433
pub mod debuginfo {
431434
use super::{ValueRef};
@@ -1967,6 +1970,12 @@ extern {
19671970
pub fn LLVMGetDiagInfoKind(DI: DiagnosticInfoRef) -> DiagnosticKind;
19681971

19691972
pub fn LLVMWriteDebugLocToString(C: ContextRef, DL: DebugLocRef, s: RustStringRef);
1973+
1974+
pub fn LLVMSetInlineAsmDiagnosticHandler(C: ContextRef,
1975+
H: InlineAsmDiagHandler,
1976+
CX: *mut c_void);
1977+
1978+
pub fn LLVMWriteSMDiagnosticToString(d: SMDiagnosticRef, s: RustStringRef);
19701979
}
19711980

19721981
pub fn SetInstructionCallConv(instr: ValueRef, cc: CallConv) {

src/libsyntax/ast.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -983,7 +983,8 @@ pub struct InlineAsm {
983983
pub clobbers: InternedString,
984984
pub volatile: bool,
985985
pub alignstack: bool,
986-
pub dialect: AsmDialect
986+
pub dialect: AsmDialect,
987+
pub expn_id: u32,
987988
}
988989

989990
/// represents an argument in a function header

src/libsyntax/codemap.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ pub struct ExpnInfo {
224224
}
225225

226226
#[deriving(PartialEq, Eq, Clone, Show, Hash)]
227-
pub struct ExpnId(u32);
227+
pub struct ExpnId(pub u32);
228228

229229
pub static NO_EXPANSION: ExpnId = ExpnId(-1);
230230

src/libsyntax/ext/asm.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
*/
1414

1515
use ast;
16+
use codemap;
1617
use codemap::Span;
1718
use ext::base;
1819
use ext::base::*;
@@ -198,6 +199,15 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
198199
}
199200
}
200201

202+
let codemap::ExpnId(expn_id) = cx.codemap().record_expansion(codemap::ExpnInfo {
203+
call_site: sp,
204+
callee: codemap::NameAndSpan {
205+
name: "asm".to_string(),
206+
format: codemap::MacroBang,
207+
span: None,
208+
},
209+
});
210+
201211
MacExpr::new(P(ast::Expr {
202212
id: ast::DUMMY_NODE_ID,
203213
node: ast::ExprInlineAsm(ast::InlineAsm {
@@ -208,7 +218,8 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
208218
clobbers: token::intern_and_get_ident(cons.as_slice()),
209219
volatile: volatile,
210220
alignstack: alignstack,
211-
dialect: dialect
221+
dialect: dialect,
222+
expn_id: expn_id,
212223
}),
213224
span: sp
214225
}))

src/libsyntax/fold.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,7 +1279,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
12791279
clobbers,
12801280
volatile,
12811281
alignstack,
1282-
dialect
1282+
dialect,
1283+
expn_id,
12831284
}) => ExprInlineAsm(InlineAsm {
12841285
inputs: inputs.move_map(|(c, input)| {
12851286
(c, folder.fold_expr(input))
@@ -1292,7 +1293,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
12921293
clobbers: clobbers,
12931294
volatile: volatile,
12941295
alignstack: alignstack,
1295-
dialect: dialect
1296+
dialect: dialect,
1297+
expn_id: expn_id,
12961298
}),
12971299
ExprMac(mac) => ExprMac(folder.fold_mac(mac)),
12981300
ExprStruct(path, fields, maybe_expr) => {

src/rustllvm/RustWrapper.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,3 +871,18 @@ extern "C" void LLVMWriteDebugLocToString(
871871
raw_rust_string_ostream os(str);
872872
unwrap(dl)->print(*unwrap(C), os);
873873
}
874+
875+
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef)
876+
877+
extern "C" void LLVMSetInlineAsmDiagnosticHandler(
878+
LLVMContextRef C,
879+
LLVMContext::InlineAsmDiagHandlerTy H,
880+
void *CX)
881+
{
882+
unwrap(C)->setInlineAsmDiagnosticHandler(H, CX);
883+
}
884+
885+
extern "C" void LLVMWriteSMDiagnosticToString(LLVMSMDiagnosticRef d, RustStringRef str) {
886+
raw_rust_string_ostream os(str);
887+
unwrap(d)->print("", os);
888+
}

src/rustllvm/rustllvm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ void LLVMRustSetLastError(const char*);
7373
typedef struct OpaqueRustString *RustStringRef;
7474
typedef struct LLVMOpaqueTwine *LLVMTwineRef;
7575
typedef struct LLVMOpaqueDebugLoc *LLVMDebugLocRef;
76+
typedef struct LLVMOpaqueSMDiagnostic *LLVMSMDiagnosticRef;
7677

7778
extern "C" void
7879
rust_llvm_string_write_impl(RustStringRef str, const char *ptr, size_t size);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
//
11+
// compile-flags: -C codegen-units=2
12+
// error-pattern: build without -C codegen-units for more exact errors
13+
14+
#![feature(asm)]
15+
16+
fn main() {
17+
unsafe {
18+
asm!("nowayisthisavalidinstruction");
19+
}
20+
}

src/test/compile-fail/asm-src-loc.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(asm)]
12+
13+
fn main() {
14+
unsafe {
15+
asm!("nowayisthisavalidinstruction"); //~ ERROR invalid instruction mnemonic
16+
}
17+
}

0 commit comments

Comments
 (0)