Improve inline asm error diagnostics
This commit is contained in:
parent
96dd4690c3
commit
b78b15665b
@ -191,6 +191,11 @@ pub struct Parser<'a> {
|
||||
append_newline: bool,
|
||||
/// Whether this formatting string is a literal or it comes from a macro.
|
||||
is_literal: bool,
|
||||
/// Start position of the current line.
|
||||
cur_line_start: usize,
|
||||
/// Start and end byte offset of every line of the format string. Excludes
|
||||
/// newline characters and leading whitespace.
|
||||
pub line_spans: Vec<InnerSpan>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Parser<'a> {
|
||||
@ -235,10 +240,15 @@ impl<'a> Iterator for Parser<'a> {
|
||||
None
|
||||
}
|
||||
}
|
||||
'\n' => Some(String(self.string(pos))),
|
||||
_ => Some(String(self.string(pos))),
|
||||
}
|
||||
} else {
|
||||
if self.is_literal && self.cur_line_start != self.input.len() {
|
||||
let start = self.to_span_index(self.cur_line_start);
|
||||
let end = self.to_span_index(self.input.len());
|
||||
self.line_spans.push(start.to(end));
|
||||
self.cur_line_start = self.input.len();
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
@ -266,6 +276,8 @@ impl<'a> Parser<'a> {
|
||||
last_opening_brace: None,
|
||||
append_newline,
|
||||
is_literal,
|
||||
cur_line_start: 0,
|
||||
line_spans: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
@ -433,7 +445,17 @@ impl<'a> Parser<'a> {
|
||||
'{' | '}' => {
|
||||
return &self.input[start..pos];
|
||||
}
|
||||
'\n' if self.is_literal => {
|
||||
let start = self.to_span_index(self.cur_line_start);
|
||||
let end = self.to_span_index(pos);
|
||||
self.line_spans.push(start.to(end));
|
||||
self.cur_line_start = pos + 1;
|
||||
self.cur.next();
|
||||
}
|
||||
_ => {
|
||||
if self.is_literal && pos == self.cur_line_start && c.is_whitespace() {
|
||||
self.cur_line_start = pos + c.len_utf8();
|
||||
}
|
||||
self.cur.next();
|
||||
}
|
||||
}
|
||||
|
@ -1252,7 +1252,7 @@ pub enum ExprKind {
|
||||
Ret(Option<P<Expr>>),
|
||||
|
||||
/// Output of the `asm!()` macro.
|
||||
InlineAsm(InlineAsm),
|
||||
InlineAsm(P<InlineAsm>),
|
||||
/// Output of the `llvm_asm!()` macro.
|
||||
LlvmInlineAsm(P<LlvmInlineAsm>),
|
||||
|
||||
@ -1971,6 +1971,7 @@ pub struct InlineAsm {
|
||||
pub template: Vec<InlineAsmTemplatePiece>,
|
||||
pub operands: Vec<(InlineAsmOperand, Span)>,
|
||||
pub options: InlineAsmOptions,
|
||||
pub line_spans: Vec<Span>,
|
||||
}
|
||||
|
||||
/// Inline assembly dialect.
|
||||
|
@ -1265,7 +1265,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
let operands = self.arena.alloc_from_iter(operands);
|
||||
let template = self.arena.alloc_from_iter(asm.template.iter().cloned());
|
||||
let hir_asm = hir::InlineAsm { template, operands, options: asm.options };
|
||||
let line_spans = self.arena.alloc_slice(&asm.line_spans[..]);
|
||||
let hir_asm = hir::InlineAsm { template, operands, options: asm.options, line_spans };
|
||||
hir::ExprKind::InlineAsm(self.arena.alloc(hir_asm))
|
||||
}
|
||||
|
||||
|
@ -513,10 +513,16 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast
|
||||
}
|
||||
}
|
||||
|
||||
let inline_asm = ast::InlineAsm { template, operands, options: args.options };
|
||||
let line_spans = if parser.line_spans.is_empty() {
|
||||
vec![template_sp]
|
||||
} else {
|
||||
parser.line_spans.iter().map(|span| template_span.from_inner(*span)).collect()
|
||||
};
|
||||
|
||||
let inline_asm = ast::InlineAsm { template, operands, options: args.options, line_spans };
|
||||
P(ast::Expr {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
kind: ast::ExprKind::InlineAsm(inline_asm),
|
||||
kind: ast::ExprKind::InlineAsm(P(inline_asm)),
|
||||
span: sp,
|
||||
attrs: ast::AttrVec::new(),
|
||||
tokens: None,
|
||||
|
@ -14,7 +14,7 @@ use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{Pos, Span};
|
||||
use rustc_target::abi::*;
|
||||
use rustc_target::asm::*;
|
||||
|
||||
@ -97,7 +97,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
ia.volatile,
|
||||
ia.alignstack,
|
||||
ia.dialect,
|
||||
span,
|
||||
&[span],
|
||||
);
|
||||
if r.is_none() {
|
||||
return false;
|
||||
@ -119,7 +119,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
template: &[InlineAsmTemplatePiece],
|
||||
operands: &[InlineAsmOperandRef<'tcx, Self>],
|
||||
options: InlineAsmOptions,
|
||||
span: Span,
|
||||
line_spans: &[Span],
|
||||
) {
|
||||
let asm_arch = self.tcx.sess.asm_arch.unwrap();
|
||||
|
||||
@ -286,9 +286,9 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
volatile,
|
||||
alignstack,
|
||||
dialect,
|
||||
span,
|
||||
line_spans,
|
||||
)
|
||||
.unwrap_or_else(|| span_bug!(span, "LLVM asm constraint validation failed"));
|
||||
.unwrap_or_else(|| span_bug!(line_spans[0], "LLVM asm constraint validation failed"));
|
||||
|
||||
if options.contains(InlineAsmOptions::PURE) {
|
||||
if options.contains(InlineAsmOptions::NOMEM) {
|
||||
@ -340,7 +340,7 @@ fn inline_asm_call(
|
||||
volatile: bool,
|
||||
alignstack: bool,
|
||||
dia: LlvmAsmDialect,
|
||||
span: Span,
|
||||
line_spans: &[Span],
|
||||
) -> Option<&'ll Value> {
|
||||
let volatile = if volatile { llvm::True } else { llvm::False };
|
||||
let alignstack = if alignstack { llvm::True } else { llvm::False };
|
||||
@ -381,8 +381,24 @@ fn inline_asm_call(
|
||||
key.len() as c_uint,
|
||||
);
|
||||
|
||||
let val: &'ll Value = bx.const_i32(span.ctxt().outer_expn().as_u32() as i32);
|
||||
llvm::LLVMSetMetadata(call, kind, llvm::LLVMMDNodeInContext(bx.llcx, &val, 1));
|
||||
// srcloc contains one integer for each line of assembly code.
|
||||
// Unfortunately this isn't enough to encode a full span so instead
|
||||
// we just encode the start position of each line.
|
||||
// FIXME: Figure out a way to pass the entire line spans.
|
||||
let mut srcloc = vec![];
|
||||
if dia == LlvmAsmDialect::Intel && line_spans.len() > 1 {
|
||||
// LLVM inserts an extra line to add the ".intel_syntax", so add
|
||||
// a dummy srcloc entry for it.
|
||||
//
|
||||
// Don't do this if we only have 1 line span since that may be
|
||||
// due to the asm template string coming from a macro. LLVM will
|
||||
// default to the first srcloc for lines that don't have an
|
||||
// associated srcloc.
|
||||
srcloc.push(bx.const_i32(0));
|
||||
}
|
||||
srcloc.extend(line_spans.iter().map(|span| bx.const_i32(span.lo().to_u32() as i32)));
|
||||
let md = llvm::LLVMMDNodeInContext(bx.llcx, srcloc.as_ptr(), srcloc.len() as u32);
|
||||
llvm::LLVMSetMetadata(call, kind, md);
|
||||
|
||||
Some(call)
|
||||
} else {
|
||||
|
@ -23,6 +23,7 @@ use rustc_middle::bug;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::{self, Lto, OutputType, Passes, Sanitizer, SwitchWithOptPath};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::InnerSpan;
|
||||
use rustc_target::spec::{CodeModel, RelocModel};
|
||||
|
||||
use libc::{c_char, c_int, c_uint, c_void, size_t};
|
||||
@ -238,12 +239,19 @@ impl<'a> Drop for DiagnosticHandlers<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn report_inline_asm(
|
||||
fn report_inline_asm(
|
||||
cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
msg: &str,
|
||||
cookie: c_uint,
|
||||
msg: String,
|
||||
mut cookie: c_uint,
|
||||
source: Option<(String, Vec<InnerSpan>)>,
|
||||
) {
|
||||
cgcx.diag_emitter.inline_asm_error(cookie as u32, msg.to_owned());
|
||||
// In LTO build we may get srcloc values from other crates which are invalid
|
||||
// since they use a different source map. To be safe we just suppress these
|
||||
// in LTO builds.
|
||||
if matches!(cgcx.lto, Lto::Fat | Lto::Thin) {
|
||||
cookie = 0;
|
||||
}
|
||||
cgcx.diag_emitter.inline_asm_error(cookie as u32, msg, source);
|
||||
}
|
||||
|
||||
unsafe extern "C" fn inline_asm_handler(diag: &SMDiagnostic, user: *const c_void, cookie: c_uint) {
|
||||
@ -252,10 +260,37 @@ unsafe extern "C" fn inline_asm_handler(diag: &SMDiagnostic, user: *const c_void
|
||||
}
|
||||
let (cgcx, _) = *(user as *const (&CodegenContext<LlvmCodegenBackend>, &Handler));
|
||||
|
||||
let msg = llvm::build_string(|s| llvm::LLVMRustWriteSMDiagnosticToString(diag, s))
|
||||
.expect("non-UTF8 SMDiagnostic");
|
||||
// Recover the post-substitution assembly code from LLVM for better
|
||||
// diagnostics.
|
||||
let mut have_source = false;
|
||||
let mut buffer = String::new();
|
||||
let mut loc = 0;
|
||||
let mut ranges = [0; 8];
|
||||
let mut num_ranges = ranges.len() / 2;
|
||||
let msg = llvm::build_string(|msg| {
|
||||
buffer = llvm::build_string(|buffer| {
|
||||
have_source = llvm::LLVMRustUnpackSMDiagnostic(
|
||||
diag,
|
||||
msg,
|
||||
buffer,
|
||||
&mut loc,
|
||||
ranges.as_mut_ptr(),
|
||||
&mut num_ranges,
|
||||
);
|
||||
})
|
||||
.expect("non-UTF8 inline asm");
|
||||
})
|
||||
.expect("non-UTF8 SMDiagnostic");
|
||||
|
||||
report_inline_asm(cgcx, &msg, cookie);
|
||||
let source = have_source.then(|| {
|
||||
let mut spans = vec![InnerSpan::new(loc as usize, loc as usize)];
|
||||
for i in 0..num_ranges {
|
||||
spans.push(InnerSpan::new(ranges[i * 2] as usize, ranges[i * 2 + 1] as usize));
|
||||
}
|
||||
(buffer, spans)
|
||||
});
|
||||
|
||||
report_inline_asm(cgcx, msg, cookie, source);
|
||||
}
|
||||
|
||||
unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void) {
|
||||
@ -266,7 +301,7 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
|
||||
|
||||
match llvm::diagnostic::Diagnostic::unpack(info) {
|
||||
llvm::diagnostic::InlineAsm(inline) => {
|
||||
report_inline_asm(cgcx, &llvm::twine_to_string(inline.message), inline.cookie);
|
||||
report_inline_asm(cgcx, llvm::twine_to_string(inline.message), inline.cookie, None);
|
||||
}
|
||||
|
||||
llvm::diagnostic::Optimization(opt) => {
|
||||
|
@ -2070,7 +2070,14 @@ extern "C" {
|
||||
);
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn LLVMRustWriteSMDiagnosticToString(d: &SMDiagnostic, s: &RustString);
|
||||
pub fn LLVMRustUnpackSMDiagnostic(
|
||||
d: &SMDiagnostic,
|
||||
message_out: &RustString,
|
||||
buffer_out: &RustString,
|
||||
loc_out: &mut c_uint,
|
||||
ranges_out: *mut c_uint,
|
||||
num_ranges: &mut usize,
|
||||
) -> bool;
|
||||
|
||||
pub fn LLVMRustWriteArchive(
|
||||
Dst: *const c_char,
|
||||
|
@ -31,9 +31,9 @@ use rustc_session::cgu_reuse_tracker::CguReuseTracker;
|
||||
use rustc_session::config::{self, CrateType, Lto, OutputFilenames, OutputType};
|
||||
use rustc_session::config::{Passes, Sanitizer, SwitchWithOptPath};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::hygiene::ExpnId;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::{BytePos, FileName, InnerSpan, Pos, Span};
|
||||
use rustc_target::spec::{MergeFunctions, PanicStrategy};
|
||||
|
||||
use std::any::Any;
|
||||
@ -1551,7 +1551,7 @@ fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B>
|
||||
|
||||
enum SharedEmitterMessage {
|
||||
Diagnostic(Diagnostic),
|
||||
InlineAsmError(u32, String),
|
||||
InlineAsmError(u32, String, Option<(String, Vec<InnerSpan>)>),
|
||||
AbortIfErrors,
|
||||
Fatal(String),
|
||||
}
|
||||
@ -1572,8 +1572,13 @@ impl SharedEmitter {
|
||||
(SharedEmitter { sender }, SharedEmitterMain { receiver })
|
||||
}
|
||||
|
||||
pub fn inline_asm_error(&self, cookie: u32, msg: String) {
|
||||
drop(self.sender.send(SharedEmitterMessage::InlineAsmError(cookie, msg)));
|
||||
pub fn inline_asm_error(
|
||||
&self,
|
||||
cookie: u32,
|
||||
msg: String,
|
||||
source: Option<(String, Vec<InnerSpan>)>,
|
||||
) {
|
||||
drop(self.sender.send(SharedEmitterMessage::InlineAsmError(cookie, msg, source)));
|
||||
}
|
||||
|
||||
pub fn fatal(&self, msg: &str) {
|
||||
@ -1626,8 +1631,30 @@ impl SharedEmitterMain {
|
||||
}
|
||||
handler.emit_diagnostic(&d);
|
||||
}
|
||||
Ok(SharedEmitterMessage::InlineAsmError(cookie, msg)) => {
|
||||
sess.span_err(ExpnId::from_u32(cookie).expn_data().call_site, &msg)
|
||||
Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, source)) => {
|
||||
let msg = msg.strip_prefix("error: ").unwrap_or(&msg);
|
||||
|
||||
// If the cookie is 0 then we don't have span information.
|
||||
let mut err = if cookie == 0 {
|
||||
sess.struct_err(&msg)
|
||||
} else {
|
||||
let pos = BytePos::from_u32(cookie);
|
||||
let span = Span::with_root_ctxt(pos, pos);
|
||||
sess.struct_span_err(span, &msg)
|
||||
};
|
||||
|
||||
// Point to the generated assembly if it is available.
|
||||
if let Some((buffer, spans)) = source {
|
||||
let source = sess
|
||||
.source_map()
|
||||
.new_source_file(FileName::inline_asm_source_code(&buffer), buffer);
|
||||
let source_span = Span::with_root_ctxt(source.start_pos, source.end_pos);
|
||||
let spans: Vec<_> =
|
||||
spans.iter().map(|sp| source_span.from_inner(*sp)).collect();
|
||||
err.span_note(spans, "instantiated into assembly here");
|
||||
}
|
||||
|
||||
err.emit();
|
||||
}
|
||||
Ok(SharedEmitterMessage::AbortIfErrors) => {
|
||||
sess.abort_if_errors();
|
||||
|
@ -831,6 +831,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
template: &[ast::InlineAsmTemplatePiece],
|
||||
operands: &[mir::InlineAsmOperand<'tcx>],
|
||||
options: ast::InlineAsmOptions,
|
||||
line_spans: &[Span],
|
||||
destination: Option<mir::BasicBlock>,
|
||||
) {
|
||||
let span = terminator.source_info.span;
|
||||
@ -931,7 +932,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
})
|
||||
.collect();
|
||||
|
||||
bx.codegen_inline_asm(template, &operands, options, span);
|
||||
bx.codegen_inline_asm(template, &operands, options, line_spans);
|
||||
|
||||
if let Some(target) = destination {
|
||||
helper.funclet_br(self, &mut bx, target);
|
||||
@ -1034,7 +1035,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
bug!("borrowck false edges in codegen")
|
||||
}
|
||||
|
||||
mir::TerminatorKind::InlineAsm { template, ref operands, options, destination } => {
|
||||
mir::TerminatorKind::InlineAsm {
|
||||
template,
|
||||
ref operands,
|
||||
options,
|
||||
line_spans,
|
||||
destination,
|
||||
} => {
|
||||
self.codegen_asm_terminator(
|
||||
helper,
|
||||
bx,
|
||||
@ -1042,6 +1049,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
template,
|
||||
operands,
|
||||
options,
|
||||
line_spans,
|
||||
destination,
|
||||
);
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ pub trait AsmBuilderMethods<'tcx>: BackendTypes {
|
||||
template: &[InlineAsmTemplatePiece],
|
||||
operands: &[InlineAsmOperandRef<'tcx, Self>],
|
||||
options: InlineAsmOptions,
|
||||
span: Span,
|
||||
line_spans: &[Span],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -2106,6 +2106,7 @@ pub struct InlineAsm<'hir> {
|
||||
pub template: &'hir [InlineAsmTemplatePiece],
|
||||
pub operands: &'hir [InlineAsmOperand<'hir>],
|
||||
pub options: InlineAsmOptions,
|
||||
pub line_spans: &'hir [Span],
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic, PartialEq)]
|
||||
|
@ -1193,6 +1193,10 @@ pub enum TerminatorKind<'tcx> {
|
||||
/// Miscellaneous options for the inline assembly.
|
||||
options: InlineAsmOptions,
|
||||
|
||||
/// Source spans for each line of the inline assembly code. These are
|
||||
/// used to map assembler errors back to the line in the source code.
|
||||
line_spans: &'tcx [Span],
|
||||
|
||||
/// Destination block after the inline assembly returns, unless it is
|
||||
/// diverging (InlineAsmOptions::NORETURN).
|
||||
destination: Option<BasicBlock>,
|
||||
@ -1595,7 +1599,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
}
|
||||
FalseEdges { .. } => write!(fmt, "falseEdges"),
|
||||
FalseUnwind { .. } => write!(fmt, "falseUnwind"),
|
||||
InlineAsm { template, ref operands, options, destination: _ } => {
|
||||
InlineAsm { template, ref operands, options, .. } => {
|
||||
write!(fmt, "asm!(\"{}\"", InlineAsmTemplatePiece::to_string(template))?;
|
||||
for op in operands {
|
||||
write!(fmt, ", ")?;
|
||||
|
@ -78,9 +78,13 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
|
||||
FalseEdges { real_target, imaginary_target }
|
||||
}
|
||||
FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind },
|
||||
InlineAsm { template, ref operands, options, destination } => {
|
||||
InlineAsm { template, operands: operands.fold_with(folder), options, destination }
|
||||
}
|
||||
InlineAsm { template, ref operands, options, line_spans, destination } => InlineAsm {
|
||||
template,
|
||||
operands: operands.fold_with(folder),
|
||||
options,
|
||||
line_spans,
|
||||
destination,
|
||||
},
|
||||
};
|
||||
Terminator { source_info: self.source_info, kind }
|
||||
}
|
||||
|
@ -535,6 +535,7 @@ macro_rules! make_mir_visitor {
|
||||
template: _,
|
||||
operands,
|
||||
options: _,
|
||||
line_spans: _,
|
||||
destination: _,
|
||||
} => {
|
||||
for op in operands {
|
||||
|
@ -183,7 +183,13 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
TerminatorKind::InlineAsm { template: _, ref operands, options: _, destination: _ } => {
|
||||
TerminatorKind::InlineAsm {
|
||||
template: _,
|
||||
ref operands,
|
||||
options: _,
|
||||
line_spans: _,
|
||||
destination: _,
|
||||
} => {
|
||||
for op in operands {
|
||||
match *op {
|
||||
InlineAsmOperand::In { reg: _, ref value }
|
||||
|
@ -724,7 +724,13 @@ impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tc
|
||||
self.mutate_place(loc, (resume_arg, span), Deep, JustWrite, flow_state);
|
||||
}
|
||||
|
||||
TerminatorKind::InlineAsm { template: _, ref operands, options: _, destination: _ } => {
|
||||
TerminatorKind::InlineAsm {
|
||||
template: _,
|
||||
ref operands,
|
||||
options: _,
|
||||
line_spans: _,
|
||||
destination: _,
|
||||
} => {
|
||||
for op in operands {
|
||||
match *op {
|
||||
InlineAsmOperand::In { reg: _, ref value }
|
||||
|
@ -482,7 +482,7 @@ impl Direction for Forward {
|
||||
}
|
||||
}
|
||||
|
||||
InlineAsm { template: _, operands: _, options: _, destination } => {
|
||||
InlineAsm { template: _, operands: _, options: _, line_spans: _, destination } => {
|
||||
if let Some(target) = destination {
|
||||
propagate(target, exit_state);
|
||||
}
|
||||
|
@ -411,7 +411,13 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||
self.gather_init(destination.as_ref(), InitKind::NonPanicPathOnly);
|
||||
}
|
||||
}
|
||||
TerminatorKind::InlineAsm { template: _, ref operands, options: _, destination: _ } => {
|
||||
TerminatorKind::InlineAsm {
|
||||
template: _,
|
||||
ref operands,
|
||||
options: _,
|
||||
line_spans: _,
|
||||
destination: _
|
||||
} => {
|
||||
for op in operands {
|
||||
match *op {
|
||||
InlineAsmOperand::In { reg: _, ref value }
|
||||
|
@ -310,7 +310,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
);
|
||||
block.unit()
|
||||
}
|
||||
ExprKind::InlineAsm { template, operands, options } => {
|
||||
ExprKind::InlineAsm { template, operands, options, line_spans } => {
|
||||
use crate::hair;
|
||||
use rustc_middle::mir;
|
||||
let operands = operands
|
||||
@ -368,6 +368,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
template,
|
||||
operands,
|
||||
options,
|
||||
line_spans,
|
||||
destination: if options.contains(InlineAsmOptions::NORETURN) {
|
||||
None
|
||||
} else {
|
||||
|
@ -513,6 +513,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
|
||||
})
|
||||
.collect(),
|
||||
options: asm.options,
|
||||
line_spans: asm.line_spans,
|
||||
},
|
||||
|
||||
hir::ExprKind::LlvmInlineAsm(ref asm) => ExprKind::LlvmInlineAsm {
|
||||
|
@ -283,6 +283,7 @@ crate enum ExprKind<'tcx> {
|
||||
template: &'tcx [InlineAsmTemplatePiece],
|
||||
operands: Vec<InlineAsmOperand<'tcx>>,
|
||||
options: InlineAsmOptions,
|
||||
line_spans: &'tcx [Span],
|
||||
},
|
||||
LlvmInlineAsm {
|
||||
asm: &'tcx hir::LlvmInlineAsmInner,
|
||||
|
@ -101,6 +101,8 @@ pub enum FileName {
|
||||
/// Custom sources for explicit parser calls from plugins and drivers.
|
||||
Custom(String),
|
||||
DocTest(PathBuf, isize),
|
||||
/// Post-substitution inline assembly from LLVM
|
||||
InlineAsm(u64),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for FileName {
|
||||
@ -116,6 +118,7 @@ impl std::fmt::Display for FileName {
|
||||
CliCrateAttr(_) => write!(fmt, "<crate attribute>"),
|
||||
Custom(ref s) => write!(fmt, "<{}>", s),
|
||||
DocTest(ref path, _) => write!(fmt, "{}", path.display()),
|
||||
InlineAsm(_) => write!(fmt, "<inline asm>"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -139,7 +142,8 @@ impl FileName {
|
||||
| CliCrateAttr(_)
|
||||
| Custom(_)
|
||||
| QuoteExpansion(_)
|
||||
| DocTest(_, _) => false,
|
||||
| DocTest(_, _)
|
||||
| InlineAsm(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -182,6 +186,12 @@ impl FileName {
|
||||
pub fn doc_test_source_code(path: PathBuf, line: isize) -> FileName {
|
||||
FileName::DocTest(path, line)
|
||||
}
|
||||
|
||||
pub fn inline_asm_source_code(src: &str) -> FileName {
|
||||
let mut hasher = StableHasher::new();
|
||||
src.hash(&mut hasher);
|
||||
FileName::InlineAsm(hasher.finish())
|
||||
}
|
||||
}
|
||||
|
||||
/// Spans represent a region of code, used for error reporting. Positions in spans
|
||||
|
@ -1216,10 +1216,33 @@ extern "C" void LLVMRustSetInlineAsmDiagnosticHandler(
|
||||
unwrap(C)->setInlineAsmDiagnosticHandler(H, CX);
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustWriteSMDiagnosticToString(LLVMSMDiagnosticRef D,
|
||||
RustStringRef Str) {
|
||||
RawRustStringOstream OS(Str);
|
||||
unwrap(D)->print("", OS);
|
||||
extern "C" bool LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef,
|
||||
RustStringRef MessageOut,
|
||||
RustStringRef BufferOut,
|
||||
unsigned* LocOut,
|
||||
unsigned* RangesOut,
|
||||
size_t* NumRanges) {
|
||||
SMDiagnostic& D = *unwrap(DRef);
|
||||
RawRustStringOstream MessageOS(MessageOut);
|
||||
MessageOS << D.getMessage();
|
||||
|
||||
if (D.getLoc() == SMLoc())
|
||||
return false;
|
||||
|
||||
const SourceMgr &LSM = *D.getSourceMgr();
|
||||
const MemoryBuffer *LBuf = LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
|
||||
LLVMRustStringWriteImpl(BufferOut, LBuf->getBufferStart(), LBuf->getBufferSize());
|
||||
|
||||
*LocOut = D.getLoc().getPointer() - LBuf->getBufferStart();
|
||||
|
||||
*NumRanges = std::min(*NumRanges, D.getRanges().size());
|
||||
size_t LineStart = *LocOut - (size_t)D.getColumnNo();
|
||||
for (size_t i = 0; i < *NumRanges; i++) {
|
||||
RangesOut[i * 2] = LineStart + D.getRanges()[i].first;
|
||||
RangesOut[i * 2 + 1] = LineStart + D.getRanges()[i].second;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" LLVMValueRef LLVMRustBuildCleanupPad(LLVMBuilderRef B,
|
||||
|
41
src/test/ui/asm/srcloc.rs
Normal file
41
src/test/ui/asm/srcloc.rs
Normal file
@ -0,0 +1,41 @@
|
||||
// no-system-llvm
|
||||
// only-x86_64
|
||||
// build-fail
|
||||
|
||||
#![feature(asm)]
|
||||
|
||||
// Checks that inline asm errors are mapped to the correct line in the source code.
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
asm!("invalid_instruction");
|
||||
//~^ ERROR: invalid instruction mnemonic 'invalid_instruction'
|
||||
|
||||
asm!("
|
||||
invalid_instruction
|
||||
");
|
||||
//~^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
|
||||
|
||||
asm!(r#"
|
||||
invalid_instruction
|
||||
"#);
|
||||
//~^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
|
||||
|
||||
asm!("
|
||||
mov eax, eax
|
||||
invalid_instruction
|
||||
mov eax, eax
|
||||
");
|
||||
//~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
|
||||
|
||||
asm!(r#"
|
||||
mov eax, eax
|
||||
invalid_instruction
|
||||
mov eax, eax
|
||||
"#);
|
||||
//~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
|
||||
|
||||
asm!(concat!("invalid", "_", "instruction"));
|
||||
//~^ ERROR: invalid instruction mnemonic 'invalid_instruction'
|
||||
}
|
||||
}
|
74
src/test/ui/asm/srcloc.stderr
Normal file
74
src/test/ui/asm/srcloc.stderr
Normal file
@ -0,0 +1,74 @@
|
||||
error: invalid instruction mnemonic 'invalid_instruction'
|
||||
--> $DIR/srcloc.rs:11:15
|
||||
|
|
||||
LL | asm!("invalid_instruction");
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:2:2
|
||||
|
|
||||
LL | invalid_instruction
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid instruction mnemonic 'invalid_instruction'
|
||||
--> $DIR/srcloc.rs:15:13
|
||||
|
|
||||
LL | invalid_instruction
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:3:13
|
||||
|
|
||||
LL | invalid_instruction
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid instruction mnemonic 'invalid_instruction'
|
||||
--> $DIR/srcloc.rs:20:13
|
||||
|
|
||||
LL | invalid_instruction
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:3:13
|
||||
|
|
||||
LL | invalid_instruction
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid instruction mnemonic 'invalid_instruction'
|
||||
--> $DIR/srcloc.rs:26:13
|
||||
|
|
||||
LL | invalid_instruction
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:4:13
|
||||
|
|
||||
LL | invalid_instruction
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid instruction mnemonic 'invalid_instruction'
|
||||
--> $DIR/srcloc.rs:33:13
|
||||
|
|
||||
LL | invalid_instruction
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:4:13
|
||||
|
|
||||
LL | invalid_instruction
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid instruction mnemonic 'invalid_instruction'
|
||||
--> $DIR/srcloc.rs:38:14
|
||||
|
|
||||
LL | asm!(concat!("invalid", "_", "instruction"));
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:2:2
|
||||
|
|
||||
LL | invalid_instruction
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
@ -2,16 +2,19 @@ error: invalid operand in inline asm: 'int $3'
|
||||
--> $DIR/issue-23458.rs:8:9
|
||||
|
|
||||
LL | llvm_asm!("int $3");
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: <inline asm>:1:2: error: too few operands for instruction
|
||||
int
|
||||
^
|
||||
| ^
|
||||
|
||||
error: too few operands for instruction
|
||||
--> $DIR/issue-23458.rs:8:9
|
||||
|
|
||||
LL | llvm_asm!("int $3");
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:1:2
|
||||
|
|
||||
LL | int
|
||||
| ^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -6,5 +6,5 @@
|
||||
|
||||
fn main() {
|
||||
unsafe { llvm_asm!(".ascii \"Xen\0\""); }
|
||||
//~^ ERROR: <inline asm>:1:9: error: expected string in '.ascii' directive
|
||||
//~^ ERROR: expected string in '.ascii' directive
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
error: <inline asm>:1:9: error: expected string in '.ascii' directive
|
||||
.ascii "Xen
|
||||
^
|
||||
|
||||
error: expected string in '.ascii' directive
|
||||
--> $DIR/issue-69092.rs:8:14
|
||||
|
|
||||
LL | unsafe { llvm_asm!(".ascii \"Xen\0\""); }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^
|
||||
|
|
||||
note: instantiated into assembly here
|
||||
--> <inline asm>:1:9
|
||||
|
|
||||
LL | .ascii "Xen
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user