Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggest including unused asm arguments in a comment to avoid error #73230

Merged
merged 2 commits into from
Jun 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/doc/unstable-book/src/library-features/asm.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
```

Expand Down Expand Up @@ -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.

Expand Down
47 changes: 29 additions & 18 deletions src/librustc_builtin_macros/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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);
Expand All @@ -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,
Expand Down Expand Up @@ -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();
}
_ => {
Expand All @@ -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();
}
}
Expand All @@ -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)),
Expand Down
2 changes: 2 additions & 0 deletions src/test/ui/asm/bad-template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
18 changes: 17 additions & 1 deletion src/test/ui/asm/bad-template.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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

2 changes: 2 additions & 0 deletions src/test/ui/asm/parse-error.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down