Skip to content

Commit

Permalink
Add a "raw" option for asm! which ignores format string specifiers
Browse files Browse the repository at this point in the history
  • Loading branch information
Amanieu committed Jun 24, 2021
1 parent 1e13a9b commit d0443bb
Show file tree
Hide file tree
Showing 8 changed files with 48 additions and 23 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_ast/src/ast.rs
Expand Up @@ -1933,6 +1933,7 @@ bitflags::bitflags! {
const NORETURN = 1 << 4;
const NOSTACK = 1 << 5;
const ATT_SYNTAX = 1 << 6;
const RAW = 1 << 7;
}
}

Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Expand Up @@ -2274,6 +2274,9 @@ impl<'a> State<'a> {
if opts.contains(InlineAsmOptions::ATT_SYNTAX) {
options.push("att_syntax");
}
if opts.contains(InlineAsmOptions::RAW) {
options.push("raw");
}
s.commasep(Inconsistent, &options, |s, &opt| {
s.word(opt);
});
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_builtin_macros/src/asm.rs
Expand Up @@ -356,6 +356,8 @@ fn parse_options<'a>(
try_set_option(p, args, sym::nostack, ast::InlineAsmOptions::NOSTACK);
} else if p.eat_keyword(sym::att_syntax) {
try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX);
} else if p.eat_keyword(kw::Raw) {
try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::RAW);
} else {
return p.unexpected();
}
Expand Down Expand Up @@ -467,6 +469,14 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
}
}

// Don't treat raw asm as a format string.
if args.options.contains(ast::InlineAsmOptions::RAW) {
template.push(ast::InlineAsmTemplatePiece::String(template_str.to_string()));
let template_num_lines = 1 + template_str.matches('\n').count();
line_spans.extend(std::iter::repeat(template_sp).take(template_num_lines));
continue;
}

let mut parser = parse::Parser::new(
template_str,
str_style,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir_pretty/src/lib.rs
Expand Up @@ -1446,6 +1446,9 @@ impl<'a> State<'a> {
if opts.contains(ast::InlineAsmOptions::ATT_SYNTAX) {
options.push("att_syntax");
}
if opts.contains(ast::InlineAsmOptions::RAW) {
options.push("raw");
}
s.commasep(Inconsistent, &options, |s, &opt| {
s.word(opt);
});
Expand Down
3 changes: 2 additions & 1 deletion src/doc/unstable-book/src/library-features/asm.md
Expand Up @@ -455,7 +455,7 @@ reg_spec := <register class> / "<explicit register>"
operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_"
reg_operand := dir_spec "(" reg_spec ")" operand_expr
operand := reg_operand / "const" const_expr / "sym" path
option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax"
option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw"
options := "options(" option *["," option] [","] ")"
asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," options] [","] ")"
```
Expand Down Expand Up @@ -775,6 +775,7 @@ Currently the following options are defined:
- `noreturn`: The `asm` block never returns, and its return type is defined as `!` (never). Behavior is undefined if execution falls through past the end of the asm code. A `noreturn` asm block behaves just like a function which doesn't return; notably, local variables in scope are not dropped before it is invoked.
- `nostack`: The `asm` block does not push data to the stack, or write to the stack red-zone (if supported by the target). If this option is *not* used then the stack pointer is guaranteed to be suitably aligned (according to the target ABI) for a function call.
- `att_syntax`: This option is only valid on x86, and causes the assembler to use the `.att_syntax prefix` mode of the GNU assembler. Register operands are substituted in with a leading `%`.
- `raw`: This causes the template string to be parsed as a raw assembly string, with no special handling for `{` and `}`. This is primarily useful when including raw assembly code from an external file using `include_str!`.

The compiler performs some additional checks on options:
- The `nomem` and `readonly` options are mutually exclusive: it is a compile-time error to specify both.
Expand Down
7 changes: 7 additions & 0 deletions src/test/codegen/asm-options.rs
Expand Up @@ -94,3 +94,10 @@ pub unsafe fn dont_remove_nonpure() {
asm!("", options(nomem));
asm!("", options(readonly));
}

// CHECK-LABEL: @raw
// CHECK: call void asm sideeffect inteldialect "{} {}", ""()
#[no_mangle]
pub unsafe fn raw() {
asm!("{} {}", options(nostack, nomem, preserves_flags, raw));
}
24 changes: 12 additions & 12 deletions src/test/ui/asm/bad-options.stderr
Expand Up @@ -28,41 +28,41 @@ error: asm outputs are not allowed with the `noreturn` option
LL | asm!("{}", out(reg) foo, options(noreturn));
| ^^^^^^^^^^^^

error: expected one of `)` or `att_syntax`, found `nomem`
error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
--> $DIR/bad-options.rs:20:25
|
LL | global_asm!("", options(nomem));
| ^^^^^ expected one of `)` or `att_syntax`
| ^^^^^ expected one of `)`, `att_syntax`, or `raw`

error: expected one of `)` or `att_syntax`, found `readonly`
error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
--> $DIR/bad-options.rs:22:25
|
LL | global_asm!("", options(readonly));
| ^^^^^^^^ expected one of `)` or `att_syntax`
| ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`

error: expected one of `)` or `att_syntax`, found `noreturn`
error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
--> $DIR/bad-options.rs:24:25
|
LL | global_asm!("", options(noreturn));
| ^^^^^^^^ expected one of `)` or `att_syntax`
| ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`

error: expected one of `)` or `att_syntax`, found `pure`
error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
--> $DIR/bad-options.rs:26:25
|
LL | global_asm!("", options(pure));
| ^^^^ expected one of `)` or `att_syntax`
| ^^^^ expected one of `)`, `att_syntax`, or `raw`

error: expected one of `)` or `att_syntax`, found `nostack`
error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
--> $DIR/bad-options.rs:28:25
|
LL | global_asm!("", options(nostack));
| ^^^^^^^ expected one of `)` or `att_syntax`
| ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`

error: expected one of `)` or `att_syntax`, found `preserves_flags`
error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
--> $DIR/bad-options.rs:30:25
|
LL | global_asm!("", options(preserves_flags));
| ^^^^^^^^^^^^^^^ expected one of `)` or `att_syntax`
| ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`

error: aborting due to 11 previous errors

20 changes: 10 additions & 10 deletions src/test/ui/asm/parse-error.stderr
Expand Up @@ -64,23 +64,23 @@ error: argument to `sym` must be a path expression
LL | asm!("{}", sym foo + bar);
| ^^^^^^^^^

error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, or `readonly`, found `foo`
error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
--> $DIR/parse-error.rs:31:26
|
LL | asm!("", options(foo));
| ^^^ expected one of 8 possible tokens
| ^^^ expected one of 9 possible tokens

error: expected one of `)` or `,`, found `foo`
--> $DIR/parse-error.rs:33:32
|
LL | asm!("", options(nomem foo));
| ^^^ expected one of `)` or `,`

error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, or `readonly`, found `foo`
error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
--> $DIR/parse-error.rs:35:33
|
LL | asm!("", options(nomem, foo));
| ^^^ expected one of 8 possible tokens
| ^^^ expected one of 9 possible tokens

error: arguments are not allowed after options
--> $DIR/parse-error.rs:37:31
Expand Down Expand Up @@ -200,23 +200,23 @@ error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
LL | global_asm!("{}", const(reg) FOO);
| ^^^ expected one of `,`, `.`, `?`, or an operator

error: expected one of `)` or `att_syntax`, found `FOO`
error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
--> $DIR/parse-error.rs:81:25
|
LL | global_asm!("", options(FOO));
| ^^^ expected one of `)` or `att_syntax`
| ^^^ expected one of `)`, `att_syntax`, or `raw`

error: expected one of `)` or `att_syntax`, found `nomem`
error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
--> $DIR/parse-error.rs:83:25
|
LL | global_asm!("", options(nomem FOO));
| ^^^^^ expected one of `)` or `att_syntax`
| ^^^^^ expected one of `)`, `att_syntax`, or `raw`

error: expected one of `)` or `att_syntax`, found `nomem`
error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
--> $DIR/parse-error.rs:85:25
|
LL | global_asm!("", options(nomem, FOO));
| ^^^^^ expected one of `)` or `att_syntax`
| ^^^^^ expected one of `)`, `att_syntax`, or `raw`

error: arguments are not allowed after options
--> $DIR/parse-error.rs:87:30
Expand Down

0 comments on commit d0443bb

Please sign in to comment.