Improve inline asm error diagnostics

This commit is contained in:
Amanieu d'Antras 2020-05-26 20:07:59 +01:00
parent 96dd4690c3
commit b78b15665b
28 changed files with 365 additions and 57 deletions

View File

@ -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();
}
}

View File

@ -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.

View File

@ -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))
}

View File

@ -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,

View File

@ -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 {

View File

@ -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) => {

View File

@ -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,

View File

@ -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();

View File

@ -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,
);
}

View File

@ -52,7 +52,7 @@ pub trait AsmBuilderMethods<'tcx>: BackendTypes {
template: &[InlineAsmTemplatePiece],
operands: &[InlineAsmOperandRef<'tcx, Self>],
options: InlineAsmOptions,
span: Span,
line_spans: &[Span],
);
}

View File

@ -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)]

View File

@ -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, ", ")?;

View File

@ -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 }
}

View File

@ -535,6 +535,7 @@ macro_rules! make_mir_visitor {
template: _,
operands,
options: _,
line_spans: _,
destination: _,
} => {
for op in operands {

View File

@ -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 }

View File

@ -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 }

View File

@ -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);
}

View File

@ -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 }

View File

@ -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 {

View File

@ -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 {

View File

@ -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,

View File

@ -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

View File

@ -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
View 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'
}
}

View 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

View File

@ -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

View File

@ -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
}

View File

@ -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