From d0443bb7c2c42d03e7a329e2e18eef779bd2e0e9 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 24 Jun 2021 16:25:44 +0100 Subject: [PATCH] Add a "raw" option for asm! which ignores format string specifiers --- compiler/rustc_ast/src/ast.rs | 1 + compiler/rustc_ast_pretty/src/pprust/state.rs | 3 +++ compiler/rustc_builtin_macros/src/asm.rs | 10 ++++++++ compiler/rustc_hir_pretty/src/lib.rs | 3 +++ .../unstable-book/src/library-features/asm.md | 3 ++- src/test/codegen/asm-options.rs | 7 ++++++ src/test/ui/asm/bad-options.stderr | 24 +++++++++---------- src/test/ui/asm/parse-error.stderr | 20 ++++++++-------- 8 files changed, 48 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index b3bac1d7ecdef..352385ca1f20f 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1933,6 +1933,7 @@ bitflags::bitflags! { const NORETURN = 1 << 4; const NOSTACK = 1 << 5; const ATT_SYNTAX = 1 << 6; + const RAW = 1 << 7; } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index b7bb896f31802..f9b735fc69d5a 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -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); }); diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index b28c6f0d99c5e..97e07d52cc31a 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -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(); } @@ -467,6 +469,14 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option 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); }); diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index 5503b3b4b32fb..2456beba486a6 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -455,7 +455,7 @@ reg_spec := / "" 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] [","] ")" ``` @@ -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. diff --git a/src/test/codegen/asm-options.rs b/src/test/codegen/asm-options.rs index 70391661b0cfb..28df0f9b8523e 100644 --- a/src/test/codegen/asm-options.rs +++ b/src/test/codegen/asm-options.rs @@ -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)); +} diff --git a/src/test/ui/asm/bad-options.stderr b/src/test/ui/asm/bad-options.stderr index 4e27a6e2cb595..9039483be4bf9 100644 --- a/src/test/ui/asm/bad-options.stderr +++ b/src/test/ui/asm/bad-options.stderr @@ -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 diff --git a/src/test/ui/asm/parse-error.stderr b/src/test/ui/asm/parse-error.stderr index afd262b851c09..33dca61dc8e34 100644 --- a/src/test/ui/asm/parse-error.stderr +++ b/src/test/ui/asm/parse-error.stderr @@ -64,11 +64,11 @@ 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 @@ -76,11 +76,11 @@ error: expected one of `)` or `,`, found `foo` 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 @@ -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