diff options
| author | Dylan DPC <dylan.dpc@gmail.com> | 2020-06-11 19:04:20 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-06-11 19:04:20 +0200 |
| commit | 8650df5dea7a27852a7fa6bd2585905abb521db7 (patch) | |
| tree | df7e39d8ffe113bd11f9cf75a54bec2157d219b8 | |
| parent | 6b418b307c0222ecceb3d82b46621a377b592c79 (diff) | |
| parent | ddacc671901359ef1cd95722af0ff23a7ca6e212 (diff) | |
| download | rust-8650df5dea7a27852a7fa6bd2585905abb521db7.tar.gz rust-8650df5dea7a27852a7fa6bd2585905abb521db7.zip | |
Rollup merge of #73230 - Amanieu:asm-unused2, r=petrochenkov
Suggest including unused asm arguments in a comment to avoid error We require all arguments to an `asm!` to be used in the template string, just like format strings. However in some cases (e.g. `black_box`) it may be desirable to have `asm!` arguments that are not used in the template string. Currently this is a hard error rather than a lint since `#[allow]` does not work on macros (#63221), so this PR suggests using the unused arguments in an asm comment as a workaround. r? @petrochenkov
| -rw-r--r-- | src/doc/unstable-book/src/library-features/asm.md | 6 | ||||
| -rw-r--r-- | src/librustc_builtin_macros/asm.rs | 47 | ||||
| -rw-r--r-- | src/test/ui/asm/bad-template.rs | 2 | ||||
| -rw-r--r-- | src/test/ui/asm/bad-template.stderr | 18 | ||||
| -rw-r--r-- | src/test/ui/asm/parse-error.stderr | 2 |
5 files changed, 54 insertions, 21 deletions
diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index ea560a6d709..fbb40f1d2f3 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -201,7 +201,7 @@ fn mul(a: u64, b: u64) -> u128 { ); } - (hi as u128) << 64 + lo as u128 + ((hi as u128) << 64) + lo as u128 } ``` @@ -382,7 +382,9 @@ The macro will initially be supported only on ARM, AArch64, x86, x86-64 and RISC The assembler template uses the same syntax as [format strings][format-syntax] (i.e. placeholders are specified by curly braces). The corresponding arguments are accessed in order, by index, or by name. However, implicit named arguments (introduced by [RFC #2795][rfc-2795]) are not supported. -As with format strings, named arguments must appear after positional arguments. Explicit register operands must appear at the end of the operand list, after any named arguments if any. Explicit register operands cannot be used by placeholders in the template string. All other operands must appear at least once in the template string, otherwise a compiler error is generated. +As with format strings, named arguments must appear after positional arguments. Explicit register operands must appear at the end of the operand list, after named arguments if any. + +Explicit register operands cannot be used by placeholders in the template string. All other named and positional operands must appear at least once in the template string, otherwise a compiler error is generated. The exact assembly code syntax is target-specific and opaque to the compiler except for the way operands are substituted into the template string to form the code passed to the assembler. diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index 6127fcc5a4b..480ee97f205 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -391,7 +391,8 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast used[*pos] = true; } - let named_pos: FxHashSet<usize> = args.named_args.values().cloned().collect(); + 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 { @@ -405,7 +406,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast let operand_idx = match arg.position { parse::ArgumentIs(idx) | parse::ArgumentImplicitlyIs(idx) => { if idx >= args.operands.len() - || named_pos.contains(&idx) + || named_pos.contains_key(&idx) || args.reg_args.contains(&idx) { let msg = format!("invalid reference to argument at index {}", idx); @@ -426,7 +427,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast }; err.note(&msg); - if named_pos.contains(&idx) { + if named_pos.contains_key(&idx) { err.span_label(args.operands[idx].1, "named argument"); err.span_note( args.operands[idx].1, @@ -480,27 +481,31 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast } } - let operands = args.operands; - let unused_operands: Vec<_> = used - .into_iter() - .enumerate() - .filter(|&(_, used)| !used) - .map(|(idx, _)| { - if named_pos.contains(&idx) { - // named argument - (operands[idx].1, "named argument never used") + let mut unused_operands = vec![]; + let mut help_str = String::new(); + for (idx, used) in used.into_iter().enumerate() { + if !used { + let msg = if let Some(sym) = named_pos.get(&idx) { + help_str.push_str(&format!(" {{{}}}", sym)); + "named argument never used" } else { - // positional argument - (operands[idx].1, "argument never used") - } - }) - .collect(); + help_str.push_str(&format!(" {{{}}}", idx)); + "argument never used" + }; + unused_operands.push((args.operands[idx].1, msg)); + } + } match unused_operands.len() { 0 => {} 1 => { let (sp, msg) = unused_operands.into_iter().next().unwrap(); let mut err = ecx.struct_span_err(sp, msg); err.span_label(sp, msg); + err.help(&format!( + "if this argument is intentionally unused, \ + consider using it in an asm comment: `\"/*{} */\"`", + help_str + )); err.emit(); } _ => { @@ -511,6 +516,11 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast for (sp, msg) in unused_operands { err.span_label(sp, msg); } + err.help(&format!( + "if these arguments are intentionally unused, \ + consider using them in an asm comment: `\"/*{} */\"`", + help_str + )); err.emit(); } } @@ -521,7 +531,8 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast parser.line_spans.iter().map(|span| template_span.from_inner(*span)).collect() }; - let inline_asm = ast::InlineAsm { template, operands, options: args.options, line_spans }; + let inline_asm = + ast::InlineAsm { template, operands: args.operands, options: args.options, line_spans }; P(ast::Expr { id: ast::DUMMY_NODE_ID, kind: ast::ExprKind::InlineAsm(P(inline_asm)), diff --git a/src/test/ui/asm/bad-template.rs b/src/test/ui/asm/bad-template.rs index 0b333eca1ab..21ce8c6236d 100644 --- a/src/test/ui/asm/bad-template.rs +++ b/src/test/ui/asm/bad-template.rs @@ -22,5 +22,7 @@ fn main() { //~^ ERROR invalid reference to argument at index 0 asm!("{:foo}", in(reg) foo); //~^ ERROR asm template modifier must be a single character + asm!("", in(reg) 0, in(reg) 1); + //~^ ERROR multiple unused asm arguments } } diff --git a/src/test/ui/asm/bad-template.stderr b/src/test/ui/asm/bad-template.stderr index 2de76ef8241..1aea7467ed0 100644 --- a/src/test/ui/asm/bad-template.stderr +++ b/src/test/ui/asm/bad-template.stderr @@ -19,6 +19,8 @@ error: argument never used | LL | asm!("{1}", in(reg) foo); | ^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` --> $DIR/bad-template.rs:13:15 @@ -46,6 +48,8 @@ error: named argument never used | LL | asm!("{}", a = in(reg) foo); | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` error: invalid reference to argument at index 1 --> $DIR/bad-template.rs:18:15 @@ -60,6 +64,8 @@ error: named argument never used | LL | asm!("{1}", a = in(reg) foo); | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` error: invalid reference to argument at index 0 --> $DIR/bad-template.rs:21:15 @@ -82,5 +88,15 @@ error: asm template modifier must be a single character LL | asm!("{:foo}", in(reg) foo); | ^^^ -error: aborting due to 10 previous errors +error: multiple unused asm arguments + --> $DIR/bad-template.rs:25:18 + | +LL | asm!("", in(reg) 0, in(reg) 1); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +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 fa422f56bec..583a1057036 100644 --- a/src/test/ui/asm/parse-error.stderr +++ b/src/test/ui/asm/parse-error.stderr @@ -127,6 +127,8 @@ error: argument never used | LL | asm!("{a}", a = const foo, a = const bar); | ^^^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` error: explicit register arguments cannot have names --> $DIR/parse-error.rs:47:18 |
