asm: Allow multiple template strings; interpret them as newline-separated

Allow the `asm!` macro to accept a series of template arguments, and
interpret them as if they were concatenated with a '\n' between them.
This allows writing an `asm!` where each line of assembly appears in a
separate template string argument.

This syntax makes it possible for rustfmt to reliably format and indent
each line of assembly, without risking changes to the inside of a
template string. It also avoids the complexity of having the user
carefully format and indent a multi-line string (including where to put
the surrounding quotes), and avoids the extra indentation and lines of a
call to `concat!`.

For example, rewriting the second example from the [blog post on the new
inline assembly
syntax](https://blog.rust-lang.org/inside-rust/2020/06/08/new-inline-asm.html)
using multiple template strings:

```rust

fn main() {
    let mut bits = [0u8; 64];
    for value in 0..=1024u64 {
        let popcnt;
        unsafe {
            asm!(
                "    popcnt {popcnt}, {v}",
                "2:",
                "    blsi rax, {v}",
                "    jz 1f",
                "    xor {v}, rax",
                "    tzcnt rax, rax",
                "    stosb",
                "    jmp 2b",
                "1:",
                v = inout(reg) value => _,
                popcnt = out(reg) popcnt,
                out("rax") _, // scratch
                inout("rdi") bits.as_mut_ptr() => _,
            );
        }
        println!("bits of {}: {:?}", value, &bits[0..popcnt]);
    }
}
```

Note that all the template strings must appear before all other
arguments; you cannot, for instance, provide a series of template
strings intermixed with the corresponding operands.

In order to get srcloc mappings right for macros that generate
multi-line string literals, create one line_span for each
line in the string literal, each pointing to the macro.

Make `rustc_parse_format::Parser::curarg` `pub`, so that we can
propagate it from one template string argument to the next.
This commit is contained in:
Josh Triplett 2020-06-14 23:33:55 -07:00
parent 50d6d4de67
commit 1078b6f942
8 changed files with 531 additions and 155 deletions

View File

@ -11,7 +11,7 @@ use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::{InnerSpan, Span};
struct AsmArgs {
template: P<ast::Expr>,
templates: Vec<P<ast::Expr>>,
operands: Vec<(ast::InlineAsmOperand, Span)>,
named_args: FxHashMap<Symbol, usize>,
reg_args: FxHashSet<usize>,
@ -52,9 +52,9 @@ fn parse_args<'a>(
return Err(err);
}
let template = p.parse_expr()?;
let first_template = p.parse_expr()?;
let mut args = AsmArgs {
template,
templates: vec![first_template],
operands: vec![],
named_args: FxHashMap::default(),
reg_args: FxHashSet::default(),
@ -62,11 +62,11 @@ fn parse_args<'a>(
options_span: None,
};
let mut first = true;
let mut allow_templates = true;
while p.token != token::Eof {
if !p.eat(&token::Comma) {
if first {
// After `asm!(""` we always expect *only* a comma...
if allow_templates {
// After a template string, we always expect *only* a comma...
let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`");
err.span_label(p.token.span, "expected `,`");
p.maybe_annotate_with_ascription(&mut err, false);
@ -76,7 +76,6 @@ fn parse_args<'a>(
return Err(p.expect(&token::Comma).err().unwrap());
}
}
first = false;
if p.token == token::Eof {
break;
} // accept trailing commas
@ -84,6 +83,7 @@ fn parse_args<'a>(
// Parse options
if p.eat(&token::Ident(sym::options, false)) {
parse_options(&mut p, &mut args)?;
allow_templates = false;
continue;
}
@ -94,6 +94,7 @@ fn parse_args<'a>(
let (ident, _) = p.token.ident().unwrap();
p.bump();
p.expect(&token::Eq)?;
allow_templates = false;
Some(ident.name)
} else {
None
@ -146,10 +147,27 @@ fn parse_args<'a>(
}
}
ast::InlineAsmOperand::Sym { expr }
} else if allow_templates {
let template = p.parse_expr()?;
// If it can't possibly expand to a string, provide diagnostics here to include other
// things it could have been.
match template.kind {
ast::ExprKind::Lit(ast::Lit { kind: ast::LitKind::Str(..), .. }) => {}
ast::ExprKind::MacCall(..) => {}
_ => {
let errstr = "expected operand, options, or additional template string";
let mut err = ecx.struct_span_err(template.span, errstr);
err.span_label(template.span, errstr);
return Err(err);
}
}
args.templates.push(template);
continue;
} else {
return Err(p.expect_one_of(&[], &[]).unwrap_err());
};
allow_templates = false;
let span = span_start.to(p.prev_token.span);
let slot = args.operands.len();
args.operands.push((op, span));
@ -331,155 +349,180 @@ fn parse_reg<'a>(
}
fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast::Expr> {
let msg = "asm template must be a string literal";
let template_sp = args.template.span;
let (template_str, template_style, template_span) =
match expr_to_spanned_string(ecx, args.template, msg) {
Ok(template) => template,
Err(err) => {
if let Some(mut err) = err {
err.emit();
}
return DummyResult::raw_expr(sp, true);
}
};
let str_style = match template_style {
ast::StrStyle::Cooked => None,
ast::StrStyle::Raw(raw) => Some(raw as usize),
};
let template_str = &template_str.as_str();
let template_snippet = ecx.source_map().span_to_snippet(template_sp).ok();
let mut parser = parse::Parser::new(
template_str,
str_style,
template_snippet,
false,
parse::ParseMode::InlineAsm,
);
let mut unverified_pieces = Vec::new();
while let Some(piece) = parser.next() {
if !parser.errors.is_empty() {
break;
} else {
unverified_pieces.push(piece);
}
}
if !parser.errors.is_empty() {
let err = parser.errors.remove(0);
let err_sp = template_span.from_inner(err.span);
let mut e = ecx
.struct_span_err(err_sp, &format!("invalid asm template string: {}", err.description));
e.span_label(err_sp, err.label + " in asm template string");
if let Some(note) = err.note {
e.note(&note);
}
if let Some((label, span)) = err.secondary_label {
let err_sp = template_span.from_inner(span);
e.span_label(err_sp, label);
}
e.emit();
return DummyResult::raw_expr(sp, true);
}
let mut template = vec![];
// Register operands are implicitly used since they are not allowed to be
// referenced in the template string.
let mut used = vec![false; args.operands.len()];
for pos in &args.reg_args {
used[*pos] = true;
}
let named_pos: FxHashMap<usize, Symbol> =
args.named_args.iter().map(|(&sym, &idx)| (idx, sym)).collect();
let mut arg_spans = parser.arg_places.iter().map(|span| template_span.from_inner(*span));
let mut template = vec![];
for piece in unverified_pieces {
match piece {
parse::Piece::String(s) => {
template.push(ast::InlineAsmTemplatePiece::String(s.to_string()))
}
parse::Piece::NextArgument(arg) => {
let span = arg_spans.next().unwrap_or(template_sp);
let mut line_spans = Vec::with_capacity(args.templates.len());
let mut curarg = 0;
let operand_idx = match arg.position {
parse::ArgumentIs(idx) | parse::ArgumentImplicitlyIs(idx) => {
if idx >= args.operands.len()
|| named_pos.contains_key(&idx)
|| args.reg_args.contains(&idx)
{
let msg = format!("invalid reference to argument at index {}", idx);
let mut err = ecx.struct_span_err(span, &msg);
err.span_label(span, "from here");
for template_expr in args.templates.into_iter() {
if !template.is_empty() {
template.push(ast::InlineAsmTemplatePiece::String("\n".to_string()));
}
let positional_args =
args.operands.len() - args.named_args.len() - args.reg_args.len();
let positional = if positional_args != args.operands.len() {
"positional "
} else {
""
};
let msg = match positional_args {
0 => format!("no {}arguments were given", positional),
1 => format!("there is 1 {}argument", positional),
x => format!("there are {} {}arguments", x, positional),
};
err.note(&msg);
if named_pos.contains_key(&idx) {
err.span_label(args.operands[idx].1, "named argument");
err.span_note(
args.operands[idx].1,
"named arguments cannot be referenced by position",
);
} else if args.reg_args.contains(&idx) {
err.span_label(args.operands[idx].1, "explicit register argument");
err.span_note(
args.operands[idx].1,
"explicit register arguments cannot be used in the asm template",
);
}
err.emit();
None
} else {
Some(idx)
}
let msg = "asm template must be a string literal";
let template_sp = template_expr.span;
let (template_str, template_style, template_span) =
match expr_to_spanned_string(ecx, template_expr, msg) {
Ok(template_part) => template_part,
Err(err) => {
if let Some(mut err) = err {
err.emit();
}
parse::ArgumentNamed(name) => match args.named_args.get(&name) {
Some(&idx) => Some(idx),
None => {
let msg = format!("there is no argument named `{}`", name);
ecx.struct_span_err(span, &msg[..]).emit();
None
}
},
};
let mut chars = arg.format.ty.chars();
let mut modifier = chars.next();
if chars.next().is_some() {
let span = arg
.format
.ty_span
.map(|sp| template_sp.from_inner(sp))
.unwrap_or(template_sp);
ecx.struct_span_err(span, "asm template modifier must be a single character")
.emit();
modifier = None;
return DummyResult::raw_expr(sp, true);
}
};
if let Some(operand_idx) = operand_idx {
used[operand_idx] = true;
template.push(ast::InlineAsmTemplatePiece::Placeholder {
operand_idx,
modifier,
span,
});
let str_style = match template_style {
ast::StrStyle::Cooked => None,
ast::StrStyle::Raw(raw) => Some(raw as usize),
};
let template_str = &template_str.as_str();
let template_snippet = ecx.source_map().span_to_snippet(template_sp).ok();
let mut parser = parse::Parser::new(
template_str,
str_style,
template_snippet,
false,
parse::ParseMode::InlineAsm,
);
parser.curarg = curarg;
let mut unverified_pieces = Vec::new();
while let Some(piece) = parser.next() {
if !parser.errors.is_empty() {
break;
} else {
unverified_pieces.push(piece);
}
}
if !parser.errors.is_empty() {
let err = parser.errors.remove(0);
let err_sp = template_span.from_inner(err.span);
let msg = &format!("invalid asm template string: {}", err.description);
let mut e = ecx.struct_span_err(err_sp, msg);
e.span_label(err_sp, err.label + " in asm template string");
if let Some(note) = err.note {
e.note(&note);
}
if let Some((label, span)) = err.secondary_label {
let err_sp = template_span.from_inner(span);
e.span_label(err_sp, label);
}
e.emit();
return DummyResult::raw_expr(sp, true);
}
curarg = parser.curarg;
let mut arg_spans = parser.arg_places.iter().map(|span| template_span.from_inner(*span));
for piece in unverified_pieces {
match piece {
parse::Piece::String(s) => {
template.push(ast::InlineAsmTemplatePiece::String(s.to_string()))
}
parse::Piece::NextArgument(arg) => {
let span = arg_spans.next().unwrap_or(template_sp);
let operand_idx = match arg.position {
parse::ArgumentIs(idx) | parse::ArgumentImplicitlyIs(idx) => {
if idx >= args.operands.len()
|| named_pos.contains_key(&idx)
|| args.reg_args.contains(&idx)
{
let msg = format!("invalid reference to argument at index {}", idx);
let mut err = ecx.struct_span_err(span, &msg);
err.span_label(span, "from here");
let positional_args = args.operands.len()
- args.named_args.len()
- args.reg_args.len();
let positional = if positional_args != args.operands.len() {
"positional "
} else {
""
};
let msg = match positional_args {
0 => format!("no {}arguments were given", positional),
1 => format!("there is 1 {}argument", positional),
x => format!("there are {} {}arguments", x, positional),
};
err.note(&msg);
if named_pos.contains_key(&idx) {
err.span_label(args.operands[idx].1, "named argument");
err.span_note(
args.operands[idx].1,
"named arguments cannot be referenced by position",
);
} else if args.reg_args.contains(&idx) {
err.span_label(
args.operands[idx].1,
"explicit register argument",
);
err.span_note(
args.operands[idx].1,
"explicit register arguments cannot be used in the asm template",
);
}
err.emit();
None
} else {
Some(idx)
}
}
parse::ArgumentNamed(name) => match args.named_args.get(&name) {
Some(&idx) => Some(idx),
None => {
let msg = format!("there is no argument named `{}`", name);
ecx.struct_span_err(span, &msg[..]).emit();
None
}
},
};
let mut chars = arg.format.ty.chars();
let mut modifier = chars.next();
if chars.next().is_some() {
let span = arg
.format
.ty_span
.map(|sp| template_sp.from_inner(sp))
.unwrap_or(template_sp);
ecx.struct_span_err(
span,
"asm template modifier must be a single character",
)
.emit();
modifier = None;
}
if let Some(operand_idx) = operand_idx {
used[operand_idx] = true;
template.push(ast::InlineAsmTemplatePiece::Placeholder {
operand_idx,
modifier,
span,
});
}
}
}
}
if parser.line_spans.is_empty() {
let template_num_lines = 1 + template_str.matches('\n').count();
line_spans.extend(std::iter::repeat(template_sp).take(template_num_lines));
} else {
line_spans.extend(parser.line_spans.iter().map(|span| template_span.from_inner(*span)));
};
}
let mut unused_operands = vec![];
@ -526,12 +569,6 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast
}
}
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: args.operands, options: args.options, line_spans };
P(ast::Expr {

View File

@ -178,7 +178,7 @@ pub struct Parser<'a> {
/// Error messages accumulated during parsing
pub errors: Vec<ParseError>,
/// Current position of implicit positional argument pointer
curarg: usize,
pub curarg: usize,
/// `Some(raw count)` when the string is "raw", used to position spans correctly
style: Option<usize>,
/// Start and end byte offset of every successfully parsed argument
@ -243,11 +243,13 @@ impl<'a> Iterator for Parser<'a> {
_ => Some(String(self.string(pos))),
}
} else {
if self.is_literal && self.cur_line_start != self.input.len() {
if self.is_literal {
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();
let span = start.to(end);
if self.line_spans.last() != Some(&span) {
self.line_spans.push(span);
}
}
None
}

View File

@ -22,5 +22,13 @@ pub fn main() {
asm!("{0}", inout(reg) b);
asm!("{0} {1}", out(reg) _, inlateout(reg) b => _);
asm!("", out("al") _, lateout("rbx") _);
asm!("inst1\ninst2");
asm!("inst1 {0}, 42\ninst2 {1}, 24", in(reg) a, out(reg) b);
asm!("inst2 {1}, 24\ninst1 {0}, 42", in(reg) a, out(reg) b);
asm!("inst1 {0}, 42\ninst2 {1}, 24", in(reg) a, out(reg) b);
asm!("inst1\ninst2");
asm!("inst1\ninst2");
asm!("inst1\n\tinst2");
asm!("inst1\ninst2\ninst3\ninst4");
}
}

View File

@ -16,5 +16,14 @@ pub fn main() {
asm!("{name}", name = inout(reg) b);
asm!("{} {}", out(reg) _, inlateout(reg) b => _);
asm!("", out("al") _, lateout("rbx") _);
asm!("inst1", "inst2");
asm!("inst1 {}, 42", "inst2 {}, 24", in(reg) a, out(reg) b);
asm!("inst2 {1}, 24", "inst1 {0}, 42", in(reg) a, out(reg) b);
asm!("inst1 {}, 42", "inst2 {name}, 24", in(reg) a, name = out(reg) b);
asm!("inst1
inst2");
asm!("inst1\ninst2");
asm!("inst1\n\tinst2");
asm!("inst1\ninst2", "inst3\ninst4");
}
}

View File

@ -13,7 +13,7 @@ fn main() {
asm!("{}" foo);
//~^ ERROR expected token: `,`
asm!("{}", foo);
//~^ ERROR expected one of
//~^ ERROR expected operand, options, or additional template string
asm!("{}", in foo);
//~^ ERROR expected `(`, found `foo`
asm!("{}", in(reg foo));
@ -52,5 +52,13 @@ fn main() {
//~^ ERROR named arguments cannot follow explicit register arguments
asm!("{1}", in("eax") foo, const bar);
//~^ ERROR positional arguments cannot follow named arguments or explicit register arguments
asm!("", options(), "");
//~^ ERROR expected one of
asm!("{}", in(reg) foo, "{}", out(reg) foo);
//~^ ERROR expected one of
asm!(format!("{{{}}}", 0), in(reg) foo);
//~^ ERROR asm template must be a string literal
asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
//~^ ERROR asm template must be a string literal
}
}

View File

@ -16,11 +16,11 @@ error: expected token: `,`
LL | asm!("{}" foo);
| ^^^ expected `,`
error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `foo`
error: expected operand, options, or additional template string
--> $DIR/parse-error.rs:15:20
|
LL | asm!("{}", foo);
| ^^^ expected one of 8 possible tokens
| ^^^ expected operand, options, or additional template string
error: expected `(`, found `foo`
--> $DIR/parse-error.rs:17:23
@ -160,5 +160,33 @@ LL | asm!("{1}", in("eax") foo, const bar);
| |
| explicit register argument
error: aborting due to 24 previous errors
error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""`
--> $DIR/parse-error.rs:55:29
|
LL | asm!("", options(), "");
| ^^ expected one of 8 possible tokens
error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
--> $DIR/parse-error.rs:57:33
|
LL | asm!("{}", in(reg) foo, "{}", out(reg) foo);
| ^^^^ expected one of 8 possible tokens
error: asm template must be a string literal
--> $DIR/parse-error.rs:59:14
|
LL | asm!(format!("{{{}}}", 0), in(reg) foo);
| ^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: asm template must be a string literal
--> $DIR/parse-error.rs:61:21
|
LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
| ^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 28 previous errors

View File

@ -40,5 +40,85 @@ fn main() {
asm!("movaps %xmm3, (%esi, 2)", options(att_syntax));
//~^ WARN: scale factor without index register is ignored
asm!(
"invalid_instruction",
);
//~^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
asm!(
"mov eax, eax",
"invalid_instruction",
"mov eax, eax",
);
//~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
asm!(
"mov eax, eax\n",
"invalid_instruction",
"mov eax, eax",
);
//~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
asm!(
"mov eax, eax",
concat!("invalid", "_", "instruction"),
"mov eax, eax",
);
//~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
asm!(
concat!("mov eax", ", ", "eax"),
concat!("invalid", "_", "instruction"),
concat!("mov eax", ", ", "eax"),
);
//~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
// Make sure template strings get separated
asm!(
"invalid_instruction1",
"invalid_instruction2",
);
//~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
//~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
asm!(
concat!(
"invalid", "_", "instruction1", "\n",
"invalid", "_", "instruction2",
),
);
//~^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
//~^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
asm!(
concat!(
"invalid", "_", "instruction1", "\n",
"invalid", "_", "instruction2",
),
concat!(
"invalid", "_", "instruction3", "\n",
"invalid", "_", "instruction4",
),
);
//~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
//~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
//~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3'
//~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4'
asm!(
concat!(
"invalid", "_", "instruction1", "\n",
"invalid", "_", "instruction2", "\n",
),
concat!(
"invalid", "_", "instruction3", "\n",
"invalid", "_", "instruction4", "\n",
),
);
//~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
//~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
//~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3'
//~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4'
}
}

View File

@ -82,5 +82,209 @@ note: instantiated into assembly here
LL | movaps %xmm3, (%esi, 2)
| ^
error: aborting due to 6 previous errors; 1 warning emitted
error: invalid instruction mnemonic 'invalid_instruction'
--> $DIR/srcloc.rs:45:14
|
LL | "invalid_instruction",
| ^
|
note: instantiated into assembly here
--> <inline asm>:2:2
|
LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
--> $DIR/srcloc.rs:51:14
|
LL | "invalid_instruction",
| ^
|
note: instantiated into assembly here
--> <inline asm>:3:1
|
LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
--> $DIR/srcloc.rs:58:14
|
LL | "invalid_instruction",
| ^
|
note: instantiated into assembly here
--> <inline asm>:4:1
|
LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
--> $DIR/srcloc.rs:65:13
|
LL | concat!("invalid", "_", "instruction"),
| ^
|
note: instantiated into assembly here
--> <inline asm>:3:1
|
LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
--> $DIR/srcloc.rs:72:13
|
LL | concat!("invalid", "_", "instruction"),
| ^
|
note: instantiated into assembly here
--> <inline asm>:3:1
|
LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction1'
--> $DIR/srcloc.rs:79:14
|
LL | "invalid_instruction1",
| ^
|
note: instantiated into assembly here
--> <inline asm>:2:2
|
LL | invalid_instruction1
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction2'
--> $DIR/srcloc.rs:80:14
|
LL | "invalid_instruction2",
| ^
|
note: instantiated into assembly here
--> <inline asm>:3:1
|
LL | invalid_instruction2
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction1'
--> $DIR/srcloc.rs:86:13
|
LL | concat!(
| ^
|
note: instantiated into assembly here
--> <inline asm>:2:2
|
LL | invalid_instruction1
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction2'
--> $DIR/srcloc.rs:86:13
|
LL | concat!(
| ^
|
note: instantiated into assembly here
--> <inline asm>:3:1
|
LL | invalid_instruction2
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction1'
--> $DIR/srcloc.rs:95:13
|
LL | concat!(
| ^
|
note: instantiated into assembly here
--> <inline asm>:2:2
|
LL | invalid_instruction1
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction2'
--> $DIR/srcloc.rs:95:13
|
LL | concat!(
| ^
|
note: instantiated into assembly here
--> <inline asm>:3:1
|
LL | invalid_instruction2
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction3'
--> $DIR/srcloc.rs:99:13
|
LL | concat!(
| ^
|
note: instantiated into assembly here
--> <inline asm>:4:1
|
LL | invalid_instruction3
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction4'
--> $DIR/srcloc.rs:99:13
|
LL | concat!(
| ^
|
note: instantiated into assembly here
--> <inline asm>:5:1
|
LL | invalid_instruction4
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction1'
--> $DIR/srcloc.rs:110:13
|
LL | concat!(
| ^
|
note: instantiated into assembly here
--> <inline asm>:2:2
|
LL | invalid_instruction1
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction2'
--> $DIR/srcloc.rs:110:13
|
LL | concat!(
| ^
|
note: instantiated into assembly here
--> <inline asm>:3:1
|
LL | invalid_instruction2
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction3'
--> $DIR/srcloc.rs:114:13
|
LL | concat!(
| ^
|
note: instantiated into assembly here
--> <inline asm>:5:1
|
LL | invalid_instruction3
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction4'
--> $DIR/srcloc.rs:114:13
|
LL | concat!(
| ^
|
note: instantiated into assembly here
--> <inline asm>:6:1
|
LL | invalid_instruction4
| ^^^^^^^^^^^^^^^^^^^^
error: aborting due to 23 previous errors; 1 warning emitted