about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-09-29 08:14:23 -0700
committerAlex Crichton <alex@alexcrichton.com>2014-09-29 08:14:23 -0700
commit7784a8d39773517da476a19562cea0ef0cd36eab (patch)
tree603ee2b90f703e8d5f83a5b9ec5651e9672421d8
parentb7c002aac149618d4ef7e2ef5a1417c85631dddb (diff)
parent8826fdfe37a7cbf901ddced1d7e2b4320e117461 (diff)
downloadrust-7784a8d39773517da476a19562cea0ef0cd36eab.tar.gz
rust-7784a8d39773517da476a19562cea0ef0cd36eab.zip
rollup merge of #17592 : kmcallister/inline-asm-loc
-rw-r--r--mk/crates.mk2
-rw-r--r--src/librustc/back/write.rs43
-rw-r--r--src/librustc/driver/driver.rs2
-rw-r--r--src/librustc/middle/trans/asm.rs14
-rw-r--r--src/librustc_llvm/lib.rs9
-rw-r--r--src/libsyntax/ast.rs5
-rw-r--r--src/libsyntax/codemap.rs14
-rw-r--r--src/libsyntax/ext/asm.rs13
-rw-r--r--src/libsyntax/fold.rs6
-rw-r--r--src/libsyntax/lib.rs1
-rw-r--r--src/rustllvm/RustWrapper.cpp15
-rw-r--r--src/rustllvm/rustllvm.h1
-rw-r--r--src/test/compile-fail/asm-src-loc-codegen-units.rs20
-rw-r--r--src/test/compile-fail/asm-src-loc.rs17
14 files changed, 148 insertions, 14 deletions
diff --git a/mk/crates.mk b/mk/crates.mk
index ed3fce775f3..9f01ff23c7f 100644
--- a/mk/crates.mk
+++ b/mk/crates.mk
@@ -71,7 +71,7 @@ DEPS_graphviz := std
 DEPS_green := std native:context_switch
 DEPS_rustuv := std native:uv native:uv_support
 DEPS_native := std
-DEPS_syntax := std term serialize log fmt_macros debug arena
+DEPS_syntax := std term serialize log fmt_macros debug arena libc
 DEPS_rustc := syntax flate arena serialize getopts rbml \
               time log graphviz debug rustc_llvm rustc_back
 DEPS_rustc_llvm := native:rustllvm libc std
diff --git a/src/librustc/back/write.rs b/src/librustc/back/write.rs
index 7242c12ae0c..7b4d1780ccd 100644
--- a/src/librustc/back/write.rs
+++ b/src/librustc/back/write.rs
@@ -16,6 +16,7 @@ use driver::session::Session;
 use driver::config;
 use llvm;
 use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef, ContextRef};
+use llvm::SMDiagnosticRef;
 use util::common::time;
 use syntax::abi;
 use syntax::codemap;
@@ -326,14 +327,40 @@ impl<'a> CodegenContext<'a> {
     }
 }
 
-struct DiagHandlerFreeVars<'a> {
+struct HandlerFreeVars<'a> {
     llcx: ContextRef,
     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::from_llvm_cookie(cookie), |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) {
-    let DiagHandlerFreeVars { llcx, cgcx }
-        = *mem::transmute::<_, *const DiagHandlerFreeVars>(user);
+    let HandlerFreeVars { llcx, cgcx }
+        = *mem::transmute::<_, *const HandlerFreeVars>(user);
 
     match llvm::diagnostic::Diagnostic::unpack(info) {
         llvm::diagnostic::Optimization(opt) => {
@@ -368,14 +395,16 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
     let tm = config.tm;
 
     // llcx doesn't outlive this function, so we can put this on the stack.
-    let fv = DiagHandlerFreeVars {
+    let fv = HandlerFreeVars {
         llcx: llcx,
         cgcx: cgcx,
     };
+    let fv = &fv as *const HandlerFreeVars as *mut c_void;
+
+    llvm::LLVMSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, fv);
+
     if !cgcx.remark.is_empty() {
-        llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler,
-                                              &fv as *const DiagHandlerFreeVars
-                                                  as *mut c_void);
+        llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, fv);
     }
 
     if config.emit_no_opt_bc {
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index 3a4b05ba00a..be0c9bb0ba3 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -557,6 +557,8 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
                               sess.opts.output_types.as_slice(),
                               outputs));
     }
+
+    sess.abort_if_errors();
 }
 
 /// Run the linker on any artifacts that resulted from the LLVM run.
diff --git a/src/librustc/middle/trans/asm.rs b/src/librustc/middle/trans/asm.rs
index a5e6d606d7b..c51e2420262 100644
--- a/src/librustc/middle/trans/asm.rs
+++ b/src/librustc/middle/trans/asm.rs
@@ -25,6 +25,7 @@ use middle::trans::type_::Type;
 use std::c_str::ToCStr;
 use std::string::String;
 use syntax::ast;
+use libc::{c_uint, c_char};
 
 // 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)
@@ -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.to_llvm_cookie());
+
+        llvm::LLVMSetMetadata(r, kind,
+            llvm::LLVMMDNodeInContext(bcx.ccx().llcx(), &val, 1));
+    }
+
     return bcx;
 
 }
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index c25ef2ca63a..401933d7058 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -424,8 +424,11 @@ pub enum DiagnosticInfo_opaque {}
 pub type DiagnosticInfoRef = *mut DiagnosticInfo_opaque;
 pub enum 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 InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint);
 
 pub mod debuginfo {
     use super::{ValueRef};
@@ -1967,6 +1970,12 @@ extern {
     pub fn LLVMGetDiagInfoKind(DI: DiagnosticInfoRef) -> DiagnosticKind;
 
     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) {
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 38d8136c1a1..0fee3ff3218 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -10,7 +10,7 @@
 
 // The Rust abstract syntax tree.
 
-use codemap::{Span, Spanned, DUMMY_SP};
+use codemap::{Span, Spanned, DUMMY_SP, ExpnId};
 use abi::Abi;
 use ast_util;
 use owned_slice::OwnedSlice;
@@ -983,7 +983,8 @@ pub struct InlineAsm {
     pub clobbers: InternedString,
     pub volatile: bool,
     pub alignstack: bool,
-    pub dialect: AsmDialect
+    pub dialect: AsmDialect,
+    pub expn_id: ExpnId,
 }
 
 /// represents an argument in a function header
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index 9072889463c..e9b2556c53e 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -26,6 +26,7 @@ source code snippets, etc.
 use serialize::{Encodable, Decodable, Encoder, Decoder};
 use std::cell::RefCell;
 use std::rc::Rc;
+use libc::c_uint;
 
 pub trait Pos {
     fn from_uint(n: uint) -> Self;
@@ -223,11 +224,22 @@ pub struct ExpnInfo {
     pub callee: NameAndSpan
 }
 
-#[deriving(PartialEq, Eq, Clone, Show, Hash)]
+#[deriving(PartialEq, Eq, Clone, Show, Hash, Encodable, Decodable)]
 pub struct ExpnId(u32);
 
 pub static NO_EXPANSION: ExpnId = ExpnId(-1);
 
+impl ExpnId {
+    pub fn from_llvm_cookie(cookie: c_uint) -> ExpnId {
+        ExpnId(cookie as u32)
+    }
+
+    pub fn to_llvm_cookie(self) -> i32 {
+        let ExpnId(cookie) = self;
+        cookie as i32
+    }
+}
+
 pub type FileName = String;
 
 pub struct FileLines {
diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs
index 4b8c3376cad..702be0c0eee 100644
--- a/src/libsyntax/ext/asm.rs
+++ b/src/libsyntax/ext/asm.rs
@@ -13,6 +13,7 @@
  */
 
 use ast;
+use codemap;
 use codemap::Span;
 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 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 {
         id: ast::DUMMY_NODE_ID,
         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()),
             volatile: volatile,
             alignstack: alignstack,
-            dialect: dialect
+            dialect: dialect,
+            expn_id: expn_id,
         }),
         span: sp
     }))
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 91a339a73f7..53be7f2c20c 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1279,7 +1279,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
                 clobbers,
                 volatile,
                 alignstack,
-                dialect
+                dialect,
+                expn_id,
             }) => ExprInlineAsm(InlineAsm {
                 inputs: inputs.move_map(|(c, 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,
                 volatile: volatile,
                 alignstack: alignstack,
-                dialect: dialect
+                dialect: dialect,
+                expn_id: expn_id,
             }),
             ExprMac(mac) => ExprMac(folder.fold_mac(mac)),
             ExprStruct(path, fields, maybe_expr) => {
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 7a504d22c1e..a4271544146 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -33,6 +33,7 @@ extern crate debug;
 #[phase(plugin, link)] extern crate log;
 extern crate serialize;
 extern crate term;
+extern crate libc;
 
 pub mod util {
     pub mod interner;
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 7896ce2ba76..1fdaa548ebe 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -871,3 +871,18 @@ extern "C" void LLVMWriteDebugLocToString(
     raw_rust_string_ostream os(str);
     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);
+}
diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h
index 54b0c2506c7..5469531c541 100644
--- a/src/rustllvm/rustllvm.h
+++ b/src/rustllvm/rustllvm.h
@@ -73,6 +73,7 @@ void LLVMRustSetLastError(const char*);
 typedef struct OpaqueRustString *RustStringRef;
 typedef struct LLVMOpaqueTwine *LLVMTwineRef;
 typedef struct LLVMOpaqueDebugLoc *LLVMDebugLocRef;
+typedef struct LLVMOpaqueSMDiagnostic *LLVMSMDiagnosticRef;
 
 extern "C" void
 rust_llvm_string_write_impl(RustStringRef str, const char *ptr, size_t size);
diff --git a/src/test/compile-fail/asm-src-loc-codegen-units.rs b/src/test/compile-fail/asm-src-loc-codegen-units.rs
new file mode 100644
index 00000000000..1b8fb32a808
--- /dev/null
+++ b/src/test/compile-fail/asm-src-loc-codegen-units.rs
@@ -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");
+    }
+}
diff --git a/src/test/compile-fail/asm-src-loc.rs b/src/test/compile-fail/asm-src-loc.rs
new file mode 100644
index 00000000000..8da6cca77cc
--- /dev/null
+++ b/src/test/compile-fail/asm-src-loc.rs
@@ -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
+    }
+}