2024-02-13 23:28:27 +00:00
|
|
|
use ast::token::IdentIsRaw;
|
2024-04-14 20:11:14 +00:00
|
|
|
use lint::BuiltinLintDiag;
|
2020-02-12 15:47:43 +00:00
|
|
|
use rustc_ast::ptr::P;
|
|
|
|
use rustc_ast::tokenstream::TokenStream;
|
2024-12-04 04:55:06 +00:00
|
|
|
use rustc_ast::{AsmMacro, token};
|
2023-05-02 15:42:36 +00:00
|
|
|
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
2023-04-30 20:45:46 +00:00
|
|
|
use rustc_errors::PResult;
|
2024-03-12 02:55:17 +00:00
|
|
|
use rustc_expand::base::*;
|
2023-05-02 15:42:36 +00:00
|
|
|
use rustc_index::bit_set::GrowableBitSet;
|
2024-12-04 04:55:06 +00:00
|
|
|
use rustc_parse::exp;
|
|
|
|
use rustc_parse::parser::{ExpKeywordPair, Parser};
|
2021-08-19 20:34:01 +00:00
|
|
|
use rustc_session::lint;
|
Move `ast::Item::ident` into `ast::ItemKind`.
`ast::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
`Trait`, `TraitAlias`, `MacroDef`, `Delegation`.
- It's always empty for these item kinds: `Use`, `ForeignMod`,
`GlobalAsm`, `Impl`, `MacCall`, `DelegationMac`.
There is a similar story for `AssocItemKind` and `ForeignItemKind`.
Some sites that handle items check for an empty ident, some don't. This
is a very C-like way of doing things, but this is Rust, we have sum
types, we can do this properly and never forget to check for the
exceptional case and never YOLO possibly empty identifiers (or possibly
dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- `ast::Item` got 8 bytes bigger. This could be avoided by boxing the
fields within some of the `ast::ItemKind` variants (specifically:
`Struct`, `Union`, `Enum`). I might do that in a follow-up; this
commit is big enough already.
- For the visitors: `FnKind` no longer needs an `ident` field because
the `Fn` within how has one.
- In the parser, the `ItemInfo` typedef is no longer needed. It was used
in various places to return an `Ident` alongside an `ItemKind`, but
now the `Ident` (if present) is within the `ItemKind`.
- In a few places I renamed identifier variables called `name` (or
`foo_name`) as `ident` (or `foo_ident`), to better match the type, and
because `name` is normally used for `Symbol`s. It's confusing to see
something like `foo_name.name`.
2025-03-20 22:47:43 +00:00
|
|
|
use rustc_span::{ErrorGuaranteed, InnerSpan, Span, Symbol, kw};
|
2021-03-24 04:52:57 +00:00
|
|
|
use rustc_target::asm::InlineAsmArch;
|
2021-04-11 19:51:28 +00:00
|
|
|
use smallvec::smallvec;
|
2024-07-28 22:13:50 +00:00
|
|
|
use {rustc_ast as ast, rustc_parse_format as parse};
|
|
|
|
|
|
|
|
use crate::errors;
|
2024-12-31 04:15:40 +00:00
|
|
|
use crate::util::{ExprToSpannedString, expr_to_spanned_string};
|
2020-02-12 15:47:43 +00:00
|
|
|
|
2021-12-17 00:40:07 +00:00
|
|
|
pub struct AsmArgs {
|
2022-01-11 02:48:22 +00:00
|
|
|
pub templates: Vec<P<ast::Expr>>,
|
|
|
|
pub operands: Vec<(ast::InlineAsmOperand, Span)>,
|
2023-04-30 19:54:43 +00:00
|
|
|
named_args: FxIndexMap<Symbol, usize>,
|
2023-05-02 15:42:36 +00:00
|
|
|
reg_args: GrowableBitSet<usize>,
|
2022-01-11 02:48:22 +00:00
|
|
|
pub clobber_abis: Vec<(Symbol, Span)>,
|
2020-05-06 13:46:01 +00:00
|
|
|
options: ast::InlineAsmOptions,
|
2022-01-11 02:48:22 +00:00
|
|
|
pub options_spans: Vec<Span>,
|
2020-02-12 15:47:43 +00:00
|
|
|
}
|
|
|
|
|
2024-07-28 13:11:14 +00:00
|
|
|
/// Used for better error messages when operand types are used that are not
|
|
|
|
/// supported by the current macro (e.g. `in` or `out` for `global_asm!`)
|
|
|
|
///
|
|
|
|
/// returns
|
|
|
|
///
|
|
|
|
/// - `Ok(true)` if the current token matches the keyword, and was expected
|
|
|
|
/// - `Ok(false)` if the current token does not match the keyword
|
|
|
|
/// - `Err(_)` if the current token matches the keyword, but was not expected
|
2024-08-04 14:42:37 +00:00
|
|
|
fn eat_operand_keyword<'a>(
|
|
|
|
p: &mut Parser<'a>,
|
2024-12-04 04:55:06 +00:00
|
|
|
exp: ExpKeywordPair,
|
2024-08-04 14:42:37 +00:00
|
|
|
asm_macro: AsmMacro,
|
|
|
|
) -> PResult<'a, bool> {
|
|
|
|
if matches!(asm_macro, AsmMacro::Asm) {
|
2024-12-04 04:55:06 +00:00
|
|
|
Ok(p.eat_keyword(exp))
|
2024-07-28 13:11:14 +00:00
|
|
|
} else {
|
|
|
|
let span = p.token.span;
|
2024-12-04 04:55:06 +00:00
|
|
|
if p.eat_keyword_noexpect(exp.kw) {
|
2024-07-28 13:11:14 +00:00
|
|
|
// in gets printed as `r#in` otherwise
|
2024-12-04 04:55:06 +00:00
|
|
|
let symbol = if exp.kw == kw::In { "in" } else { exp.kw.as_str() };
|
2024-08-04 14:42:37 +00:00
|
|
|
Err(p.dcx().create_err(errors::AsmUnsupportedOperand {
|
|
|
|
span,
|
|
|
|
symbol,
|
|
|
|
macro_name: asm_macro.macro_name(),
|
|
|
|
}))
|
2024-07-28 13:11:14 +00:00
|
|
|
} else {
|
|
|
|
Ok(false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-12 15:47:43 +00:00
|
|
|
fn parse_args<'a>(
|
compiler: fix few needless_pass_by_ref_mut clippy lints
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\asm.rs:306:28
|
306 | fn err_duplicate_option(p: &mut Parser<'_>, symbol: Symbol, span: Span) {
| ^^^^^^^^^^^^^^^ help: consider changing to: `&Parser<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\asm.rs:318:8
|
318 | p: &mut Parser<'a>,
| ^^^^^^^^^^^^^^^ help: consider changing to: `&Parser<'a>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\assert.rs:114:25
|
114 | fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> {
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'a>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\asm.rs:32:10
|
32 | ecx: &mut ExtCtxt<'a>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'a>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\test.rs:99:9
|
99 | cx: &mut ExtCtxt<'_>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\source_util.rs:237:9
|
237 | cx: &mut ExtCtxt<'_>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\format.rs:809:10
|
809 | ecx: &mut ExtCtxt<'_>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\format.rs:737:10
|
737 | ecx: &mut ExtCtxt<'a>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'a>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\format.rs:68:24
|
68 | fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, MacroInput> {
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'a>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\format.rs:607:10
|
607 | ecx: &mut ExtCtxt<'_>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\edition_panic.rs:43:9
|
43 | cx: &'cx mut ExtCtxt<'_>,
| ^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\concat_bytes.rs:11:9
|
11 | cx: &mut ExtCtxt<'_>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\cfg.rs:38:22
|
38 | fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'a>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\cfg_accessible.rs:13:28
|
13 | fn validate_input<'a>(ecx: &mut ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> {
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
2024-03-28 09:04:00 +00:00
|
|
|
ecx: &ExtCtxt<'a>,
|
2020-02-12 15:47:43 +00:00
|
|
|
sp: Span,
|
|
|
|
tts: TokenStream,
|
2024-08-04 14:42:37 +00:00
|
|
|
asm_macro: AsmMacro,
|
2022-01-27 09:44:25 +00:00
|
|
|
) -> PResult<'a, AsmArgs> {
|
2020-02-12 15:47:43 +00:00
|
|
|
let mut p = ecx.new_parser_from_tts(tts);
|
2024-08-04 14:42:37 +00:00
|
|
|
parse_asm_args(&mut p, sp, asm_macro)
|
2021-12-17 00:40:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Primarily public for rustfmt consumption.
|
|
|
|
// Internal consumers should continue to leverage `expand_asm`/`expand__global_asm`
|
|
|
|
pub fn parse_asm_args<'a>(
|
|
|
|
p: &mut Parser<'a>,
|
|
|
|
sp: Span,
|
2024-08-04 14:42:37 +00:00
|
|
|
asm_macro: AsmMacro,
|
2022-01-27 09:44:25 +00:00
|
|
|
) -> PResult<'a, AsmArgs> {
|
2024-06-18 09:43:28 +00:00
|
|
|
let dcx = p.dcx();
|
2020-02-12 15:47:43 +00:00
|
|
|
|
|
|
|
if p.token == token::Eof {
|
2023-12-18 00:15:13 +00:00
|
|
|
return Err(dcx.create_err(errors::AsmRequiresTemplate { span: sp }));
|
2020-02-12 15:47:43 +00:00
|
|
|
}
|
|
|
|
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
let first_template = p.parse_expr()?;
|
2020-02-12 15:47:43 +00:00
|
|
|
let mut args = AsmArgs {
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
templates: vec![first_template],
|
2020-02-12 15:47:43 +00:00
|
|
|
operands: vec![],
|
2023-04-30 19:54:43 +00:00
|
|
|
named_args: Default::default(),
|
|
|
|
reg_args: Default::default(),
|
2021-10-14 07:23:09 +00:00
|
|
|
clobber_abis: Vec::new(),
|
2020-05-06 13:46:01 +00:00
|
|
|
options: ast::InlineAsmOptions::empty(),
|
2020-06-12 18:31:41 +00:00
|
|
|
options_spans: vec![],
|
2020-02-12 15:47:43 +00:00
|
|
|
};
|
|
|
|
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
let mut allow_templates = true;
|
2020-02-12 15:47:43 +00:00
|
|
|
while p.token != token::Eof {
|
2024-12-04 04:55:06 +00:00
|
|
|
if !p.eat(exp!(Comma)) {
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
if allow_templates {
|
|
|
|
// After a template string, we always expect *only* a comma...
|
2023-12-18 00:15:13 +00:00
|
|
|
return Err(dcx.create_err(errors::AsmExpectedComma { span: p.token.span }));
|
2020-02-12 15:47:43 +00:00
|
|
|
} else {
|
|
|
|
// ...after that delegate to `expect` to also include the other expected tokens.
|
2024-12-04 04:55:06 +00:00
|
|
|
return Err(p.expect(exp!(Comma)).err().unwrap());
|
2020-02-12 15:47:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if p.token == token::Eof {
|
|
|
|
break;
|
|
|
|
} // accept trailing commas
|
|
|
|
|
2021-07-29 11:43:26 +00:00
|
|
|
// Parse clobber_abi
|
2024-12-04 04:55:06 +00:00
|
|
|
if p.eat_keyword(exp!(ClobberAbi)) {
|
2021-12-17 00:40:07 +00:00
|
|
|
parse_clobber_abi(p, &mut args)?;
|
2021-07-29 11:43:26 +00:00
|
|
|
allow_templates = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-02-12 15:47:43 +00:00
|
|
|
// Parse options
|
2024-12-04 04:55:06 +00:00
|
|
|
if p.eat_keyword(exp!(Options)) {
|
2024-08-04 14:42:37 +00:00
|
|
|
parse_options(p, &mut args, asm_macro)?;
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
allow_templates = false;
|
2020-02-12 15:47:43 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-03-19 07:41:43 +00:00
|
|
|
let span_start = p.token.span;
|
|
|
|
|
2020-02-12 15:47:43 +00:00
|
|
|
// Parse operand names
|
|
|
|
let name = if p.token.is_ident() && p.look_ahead(1, |t| *t == token::Eq) {
|
|
|
|
let (ident, _) = p.token.ident().unwrap();
|
|
|
|
p.bump();
|
2024-12-04 04:55:06 +00:00
|
|
|
p.expect(exp!(Eq))?;
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
allow_templates = false;
|
2020-02-12 15:47:43 +00:00
|
|
|
Some(ident.name)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut explicit_reg = false;
|
2024-12-04 04:55:06 +00:00
|
|
|
let op = if eat_operand_keyword(p, exp!(In), asm_macro)? {
|
2021-12-17 00:40:07 +00:00
|
|
|
let reg = parse_reg(p, &mut explicit_reg)?;
|
2024-12-04 04:55:06 +00:00
|
|
|
if p.eat_keyword(exp!(Underscore)) {
|
2023-12-18 00:15:13 +00:00
|
|
|
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
|
2021-08-21 14:47:24 +00:00
|
|
|
return Err(err);
|
|
|
|
}
|
2020-02-12 15:47:43 +00:00
|
|
|
let expr = p.parse_expr()?;
|
|
|
|
ast::InlineAsmOperand::In { reg, expr }
|
2024-12-04 04:55:06 +00:00
|
|
|
} else if eat_operand_keyword(p, exp!(Out), asm_macro)? {
|
2021-12-17 00:40:07 +00:00
|
|
|
let reg = parse_reg(p, &mut explicit_reg)?;
|
2024-12-04 04:55:06 +00:00
|
|
|
let expr = if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) };
|
2020-02-12 15:47:43 +00:00
|
|
|
ast::InlineAsmOperand::Out { reg, expr, late: false }
|
2024-12-04 04:55:06 +00:00
|
|
|
} else if eat_operand_keyword(p, exp!(Lateout), asm_macro)? {
|
2021-12-17 00:40:07 +00:00
|
|
|
let reg = parse_reg(p, &mut explicit_reg)?;
|
2024-12-04 04:55:06 +00:00
|
|
|
let expr = if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) };
|
2020-02-12 15:47:43 +00:00
|
|
|
ast::InlineAsmOperand::Out { reg, expr, late: true }
|
2024-12-04 04:55:06 +00:00
|
|
|
} else if eat_operand_keyword(p, exp!(Inout), asm_macro)? {
|
2021-12-17 00:40:07 +00:00
|
|
|
let reg = parse_reg(p, &mut explicit_reg)?;
|
2024-12-04 04:55:06 +00:00
|
|
|
if p.eat_keyword(exp!(Underscore)) {
|
2023-12-18 00:15:13 +00:00
|
|
|
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
|
2021-08-21 14:47:24 +00:00
|
|
|
return Err(err);
|
|
|
|
}
|
2020-02-12 15:47:43 +00:00
|
|
|
let expr = p.parse_expr()?;
|
2024-12-04 04:55:06 +00:00
|
|
|
if p.eat(exp!(FatArrow)) {
|
2020-02-12 15:47:43 +00:00
|
|
|
let out_expr =
|
2024-12-04 04:55:06 +00:00
|
|
|
if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) };
|
2020-02-12 15:47:43 +00:00
|
|
|
ast::InlineAsmOperand::SplitInOut { reg, in_expr: expr, out_expr, late: false }
|
|
|
|
} else {
|
|
|
|
ast::InlineAsmOperand::InOut { reg, expr, late: false }
|
|
|
|
}
|
2024-12-04 04:55:06 +00:00
|
|
|
} else if eat_operand_keyword(p, exp!(Inlateout), asm_macro)? {
|
2021-12-17 00:40:07 +00:00
|
|
|
let reg = parse_reg(p, &mut explicit_reg)?;
|
2024-12-04 04:55:06 +00:00
|
|
|
if p.eat_keyword(exp!(Underscore)) {
|
2023-12-18 00:15:13 +00:00
|
|
|
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
|
2021-08-21 14:47:24 +00:00
|
|
|
return Err(err);
|
|
|
|
}
|
2020-02-12 15:47:43 +00:00
|
|
|
let expr = p.parse_expr()?;
|
2024-12-04 04:55:06 +00:00
|
|
|
if p.eat(exp!(FatArrow)) {
|
2020-02-12 15:47:43 +00:00
|
|
|
let out_expr =
|
2024-12-04 04:55:06 +00:00
|
|
|
if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) };
|
2020-02-12 15:47:43 +00:00
|
|
|
ast::InlineAsmOperand::SplitInOut { reg, in_expr: expr, out_expr, late: true }
|
|
|
|
} else {
|
|
|
|
ast::InlineAsmOperand::InOut { reg, expr, late: true }
|
|
|
|
}
|
2024-12-04 04:55:06 +00:00
|
|
|
} else if eat_operand_keyword(p, exp!(Label), asm_macro)? {
|
2024-07-28 13:11:14 +00:00
|
|
|
let block = p.parse_block()?;
|
|
|
|
ast::InlineAsmOperand::Label { block }
|
2024-12-04 04:55:06 +00:00
|
|
|
} else if p.eat_keyword(exp!(Const)) {
|
2023-02-24 03:38:45 +00:00
|
|
|
let anon_const = p.parse_expr_anon_const()?;
|
2021-04-06 04:50:55 +00:00
|
|
|
ast::InlineAsmOperand::Const { anon_const }
|
2024-12-04 04:55:06 +00:00
|
|
|
} else if p.eat_keyword(exp!(Sym)) {
|
2020-02-12 15:47:43 +00:00
|
|
|
let expr = p.parse_expr()?;
|
2022-03-01 00:50:56 +00:00
|
|
|
let ast::ExprKind::Path(qself, path) = &expr.kind else {
|
2023-12-18 00:15:13 +00:00
|
|
|
let err = dcx.create_err(errors::AsmSymNoPath { span: expr.span });
|
2022-03-01 00:50:56 +00:00
|
|
|
return Err(err);
|
|
|
|
};
|
|
|
|
let sym = ast::InlineAsmSym {
|
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
qself: qself.clone(),
|
|
|
|
path: path.clone(),
|
|
|
|
};
|
|
|
|
ast::InlineAsmOperand::Sym { sym }
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
} 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 {
|
2022-10-10 02:40:56 +00:00
|
|
|
ast::ExprKind::Lit(token_lit)
|
|
|
|
if matches!(
|
|
|
|
token_lit.kind,
|
|
|
|
token::LitKind::Str | token::LitKind::StrRaw(_)
|
|
|
|
) => {}
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
ast::ExprKind::MacCall(..) => {}
|
|
|
|
_ => {
|
2023-12-18 00:15:13 +00:00
|
|
|
let err = dcx.create_err(errors::AsmExpectedOther {
|
2023-04-30 20:45:46 +00:00
|
|
|
span: template.span,
|
2024-08-04 14:42:37 +00:00
|
|
|
is_inline_asm: matches!(asm_macro, AsmMacro::Asm),
|
2023-04-30 20:45:46 +00:00
|
|
|
});
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
return Err(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
args.templates.push(template);
|
|
|
|
continue;
|
2020-06-14 21:17:51 +00:00
|
|
|
} else {
|
2024-03-15 11:36:21 +00:00
|
|
|
p.unexpected_any()?
|
2020-02-12 15:47:43 +00:00
|
|
|
};
|
|
|
|
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
allow_templates = false;
|
2020-02-12 15:47:43 +00:00
|
|
|
let span = span_start.to(p.prev_token.span);
|
|
|
|
let slot = args.operands.len();
|
|
|
|
args.operands.push((op, span));
|
|
|
|
|
2021-07-29 11:43:26 +00:00
|
|
|
// Validate the order of named, positional & explicit register operands and
|
|
|
|
// clobber_abi/options. We do this at the end once we have the full span
|
|
|
|
// of the argument available.
|
2020-02-12 15:47:43 +00:00
|
|
|
if explicit_reg {
|
|
|
|
if name.is_some() {
|
2023-12-18 00:15:13 +00:00
|
|
|
dcx.emit_err(errors::AsmExplicitRegisterName { span });
|
2020-02-12 15:47:43 +00:00
|
|
|
}
|
|
|
|
args.reg_args.insert(slot);
|
|
|
|
} else if let Some(name) = name {
|
|
|
|
if let Some(&prev) = args.named_args.get(&name) {
|
2023-12-18 00:15:13 +00:00
|
|
|
dcx.emit_err(errors::AsmDuplicateArg { span, name, prev: args.operands[prev].1 });
|
2020-02-12 15:47:43 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
args.named_args.insert(name, slot);
|
2024-09-11 21:23:56 +00:00
|
|
|
} else if !args.named_args.is_empty() || !args.reg_args.is_empty() {
|
|
|
|
let named = args.named_args.values().map(|p| args.operands[*p].1).collect();
|
|
|
|
let explicit = args.reg_args.iter().map(|p| args.operands[p].1).collect();
|
2023-04-30 20:45:46 +00:00
|
|
|
|
2024-09-11 21:23:56 +00:00
|
|
|
dcx.emit_err(errors::AsmPositionalAfter { span, named, explicit });
|
2020-02-12 15:47:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-06 13:46:01 +00:00
|
|
|
if args.options.contains(ast::InlineAsmOptions::NOMEM)
|
|
|
|
&& args.options.contains(ast::InlineAsmOptions::READONLY)
|
2020-02-12 15:47:43 +00:00
|
|
|
{
|
2020-06-12 18:31:41 +00:00
|
|
|
let spans = args.options_spans.clone();
|
2023-12-18 00:15:13 +00:00
|
|
|
dcx.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "nomem", opt2: "readonly" });
|
2020-02-12 15:47:43 +00:00
|
|
|
}
|
2020-05-06 13:46:01 +00:00
|
|
|
if args.options.contains(ast::InlineAsmOptions::PURE)
|
|
|
|
&& args.options.contains(ast::InlineAsmOptions::NORETURN)
|
2020-02-12 15:47:43 +00:00
|
|
|
{
|
2020-06-12 18:31:41 +00:00
|
|
|
let spans = args.options_spans.clone();
|
2023-12-18 00:15:13 +00:00
|
|
|
dcx.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "pure", opt2: "noreturn" });
|
2020-02-12 15:47:43 +00:00
|
|
|
}
|
2020-05-06 13:46:01 +00:00
|
|
|
if args.options.contains(ast::InlineAsmOptions::PURE)
|
|
|
|
&& !args.options.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY)
|
2020-02-12 15:47:43 +00:00
|
|
|
{
|
2020-06-12 18:39:52 +00:00
|
|
|
let spans = args.options_spans.clone();
|
2023-12-18 00:15:13 +00:00
|
|
|
dcx.emit_err(errors::AsmPureCombine { spans });
|
2020-02-12 15:47:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut have_real_output = false;
|
|
|
|
let mut outputs_sp = vec![];
|
2021-07-29 11:43:26 +00:00
|
|
|
let mut regclass_outputs = vec![];
|
2023-12-26 04:44:22 +00:00
|
|
|
let mut labels_sp = vec![];
|
2020-02-12 15:47:43 +00:00
|
|
|
for (op, op_sp) in &args.operands {
|
|
|
|
match op {
|
2021-07-29 11:43:26 +00:00
|
|
|
ast::InlineAsmOperand::Out { reg, expr, .. }
|
|
|
|
| ast::InlineAsmOperand::SplitInOut { reg, out_expr: expr, .. } => {
|
2020-02-12 15:47:43 +00:00
|
|
|
outputs_sp.push(*op_sp);
|
|
|
|
have_real_output |= expr.is_some();
|
2021-07-29 11:43:26 +00:00
|
|
|
if let ast::InlineAsmRegOrRegClass::RegClass(_) = reg {
|
|
|
|
regclass_outputs.push(*op_sp);
|
|
|
|
}
|
2020-02-12 15:47:43 +00:00
|
|
|
}
|
2021-07-29 11:43:26 +00:00
|
|
|
ast::InlineAsmOperand::InOut { reg, .. } => {
|
2020-02-12 15:47:43 +00:00
|
|
|
outputs_sp.push(*op_sp);
|
|
|
|
have_real_output = true;
|
2021-07-29 11:43:26 +00:00
|
|
|
if let ast::InlineAsmRegOrRegClass::RegClass(_) = reg {
|
|
|
|
regclass_outputs.push(*op_sp);
|
|
|
|
}
|
2020-02-12 15:47:43 +00:00
|
|
|
}
|
2023-12-26 04:44:22 +00:00
|
|
|
ast::InlineAsmOperand::Label { .. } => {
|
|
|
|
labels_sp.push(*op_sp);
|
|
|
|
}
|
2020-02-12 15:47:43 +00:00
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
2020-05-06 13:46:01 +00:00
|
|
|
if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
|
2023-12-18 00:15:13 +00:00
|
|
|
dcx.emit_err(errors::AsmPureNoOutput { spans: args.options_spans.clone() });
|
2020-02-12 15:47:43 +00:00
|
|
|
}
|
2024-10-10 23:26:21 +00:00
|
|
|
if args.options.contains(ast::InlineAsmOptions::NORETURN)
|
|
|
|
&& !outputs_sp.is_empty()
|
|
|
|
&& labels_sp.is_empty()
|
|
|
|
{
|
2023-12-18 00:15:13 +00:00
|
|
|
let err = dcx.create_err(errors::AsmNoReturn { outputs_sp });
|
2020-02-12 15:47:43 +00:00
|
|
|
// Bail out now since this is likely to confuse MIR
|
|
|
|
return Err(err);
|
|
|
|
}
|
2023-12-26 04:44:22 +00:00
|
|
|
if args.options.contains(ast::InlineAsmOptions::MAY_UNWIND) && !labels_sp.is_empty() {
|
|
|
|
dcx.emit_err(errors::AsmMayUnwind { labels_sp });
|
|
|
|
}
|
2021-10-14 07:23:09 +00:00
|
|
|
|
2024-08-04 14:42:37 +00:00
|
|
|
if !args.clobber_abis.is_empty() {
|
|
|
|
match asm_macro {
|
|
|
|
AsmMacro::GlobalAsm | AsmMacro::NakedAsm => {
|
|
|
|
let err = dcx.create_err(errors::AsmUnsupportedClobberAbi {
|
|
|
|
spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
|
|
|
|
macro_name: asm_macro.macro_name(),
|
|
|
|
});
|
2021-07-29 11:43:26 +00:00
|
|
|
|
2024-08-04 14:42:37 +00:00
|
|
|
// Bail out now since this is likely to confuse later stages
|
|
|
|
return Err(err);
|
|
|
|
}
|
|
|
|
AsmMacro::Asm => {
|
|
|
|
if !regclass_outputs.is_empty() {
|
|
|
|
dcx.emit_err(errors::AsmClobberNoReg {
|
|
|
|
spans: regclass_outputs,
|
|
|
|
clobbers: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2021-07-29 11:43:26 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-12 15:47:43 +00:00
|
|
|
|
|
|
|
Ok(args)
|
|
|
|
}
|
|
|
|
|
2020-06-17 01:10:26 +00:00
|
|
|
/// Report a duplicate option error.
|
|
|
|
///
|
|
|
|
/// This function must be called immediately after the option token is parsed.
|
|
|
|
/// Otherwise, the suggestion will be incorrect.
|
compiler: fix few needless_pass_by_ref_mut clippy lints
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\asm.rs:306:28
|
306 | fn err_duplicate_option(p: &mut Parser<'_>, symbol: Symbol, span: Span) {
| ^^^^^^^^^^^^^^^ help: consider changing to: `&Parser<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\asm.rs:318:8
|
318 | p: &mut Parser<'a>,
| ^^^^^^^^^^^^^^^ help: consider changing to: `&Parser<'a>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\assert.rs:114:25
|
114 | fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> {
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'a>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\asm.rs:32:10
|
32 | ecx: &mut ExtCtxt<'a>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'a>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\test.rs:99:9
|
99 | cx: &mut ExtCtxt<'_>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\source_util.rs:237:9
|
237 | cx: &mut ExtCtxt<'_>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\format.rs:809:10
|
809 | ecx: &mut ExtCtxt<'_>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\format.rs:737:10
|
737 | ecx: &mut ExtCtxt<'a>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'a>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\format.rs:68:24
|
68 | fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, MacroInput> {
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'a>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\format.rs:607:10
|
607 | ecx: &mut ExtCtxt<'_>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\edition_panic.rs:43:9
|
43 | cx: &'cx mut ExtCtxt<'_>,
| ^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\concat_bytes.rs:11:9
|
11 | cx: &mut ExtCtxt<'_>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\cfg.rs:38:22
|
38 | fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'a>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\cfg_accessible.rs:13:28
|
13 | fn validate_input<'a>(ecx: &mut ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> {
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
2024-03-28 09:04:00 +00:00
|
|
|
fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
|
2020-06-20 03:18:32 +00:00
|
|
|
// Tool-only output
|
2024-08-09 07:44:47 +00:00
|
|
|
let full_span = if p.token == token::Comma { span.to(p.token.span) } else { span };
|
2024-06-18 09:43:28 +00:00
|
|
|
p.dcx().emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span });
|
2020-06-14 20:38:09 +00:00
|
|
|
}
|
|
|
|
|
2024-07-25 08:05:31 +00:00
|
|
|
/// Report an invalid option error.
|
|
|
|
///
|
|
|
|
/// This function must be called immediately after the option token is parsed.
|
|
|
|
/// Otherwise, the suggestion will be incorrect.
|
2024-08-04 14:42:37 +00:00
|
|
|
fn err_unsupported_option(p: &Parser<'_>, asm_macro: AsmMacro, symbol: Symbol, span: Span) {
|
2024-07-25 08:05:31 +00:00
|
|
|
// Tool-only output
|
2024-08-09 07:44:47 +00:00
|
|
|
let full_span = if p.token == token::Comma { span.to(p.token.span) } else { span };
|
2024-08-04 14:42:37 +00:00
|
|
|
p.dcx().emit_err(errors::AsmUnsupportedOption {
|
|
|
|
span,
|
|
|
|
symbol,
|
|
|
|
full_span,
|
|
|
|
macro_name: asm_macro.macro_name(),
|
|
|
|
});
|
2024-07-25 08:05:31 +00:00
|
|
|
}
|
|
|
|
|
2020-06-17 01:10:26 +00:00
|
|
|
/// Try to set the provided option in the provided `AsmArgs`.
|
|
|
|
/// If it is already set, report a duplicate option error.
|
|
|
|
///
|
|
|
|
/// This function must be called immediately after the option token is parsed.
|
|
|
|
/// Otherwise, the error will not point to the correct spot.
|
2020-06-15 19:07:46 +00:00
|
|
|
fn try_set_option<'a>(
|
compiler: fix few needless_pass_by_ref_mut clippy lints
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\asm.rs:306:28
|
306 | fn err_duplicate_option(p: &mut Parser<'_>, symbol: Symbol, span: Span) {
| ^^^^^^^^^^^^^^^ help: consider changing to: `&Parser<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\asm.rs:318:8
|
318 | p: &mut Parser<'a>,
| ^^^^^^^^^^^^^^^ help: consider changing to: `&Parser<'a>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\assert.rs:114:25
|
114 | fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> {
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'a>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\asm.rs:32:10
|
32 | ecx: &mut ExtCtxt<'a>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'a>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\test.rs:99:9
|
99 | cx: &mut ExtCtxt<'_>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\source_util.rs:237:9
|
237 | cx: &mut ExtCtxt<'_>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\format.rs:809:10
|
809 | ecx: &mut ExtCtxt<'_>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\format.rs:737:10
|
737 | ecx: &mut ExtCtxt<'a>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'a>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\format.rs:68:24
|
68 | fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, MacroInput> {
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'a>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\format.rs:607:10
|
607 | ecx: &mut ExtCtxt<'_>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\edition_panic.rs:43:9
|
43 | cx: &'cx mut ExtCtxt<'_>,
| ^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\concat_bytes.rs:11:9
|
11 | cx: &mut ExtCtxt<'_>,
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\cfg.rs:38:22
|
38 | fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'a>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_builtin_macros\src\cfg_accessible.rs:13:28
|
13 | fn validate_input<'a>(ecx: &mut ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> {
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&ExtCtxt<'_>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
2024-03-28 09:04:00 +00:00
|
|
|
p: &Parser<'a>,
|
2020-06-15 19:07:46 +00:00
|
|
|
args: &mut AsmArgs,
|
2024-08-04 14:42:37 +00:00
|
|
|
asm_macro: AsmMacro,
|
2020-06-15 19:07:46 +00:00
|
|
|
symbol: Symbol,
|
|
|
|
option: ast::InlineAsmOptions,
|
|
|
|
) {
|
2024-08-04 14:42:37 +00:00
|
|
|
if !asm_macro.is_supported_option(option) {
|
|
|
|
err_unsupported_option(p, asm_macro, symbol, p.prev_token.span);
|
2024-07-25 08:05:31 +00:00
|
|
|
} else if args.options.contains(option) {
|
2020-06-16 19:43:03 +00:00
|
|
|
err_duplicate_option(p, symbol, p.prev_token.span);
|
2024-07-25 08:05:31 +00:00
|
|
|
} else {
|
|
|
|
args.options |= option;
|
2020-06-14 20:38:09 +00:00
|
|
|
}
|
2020-06-14 00:06:35 +00:00
|
|
|
}
|
|
|
|
|
2021-04-11 19:51:28 +00:00
|
|
|
fn parse_options<'a>(
|
|
|
|
p: &mut Parser<'a>,
|
|
|
|
args: &mut AsmArgs,
|
2024-08-04 14:42:37 +00:00
|
|
|
asm_macro: AsmMacro,
|
2022-01-27 09:44:25 +00:00
|
|
|
) -> PResult<'a, ()> {
|
2020-03-19 07:41:43 +00:00
|
|
|
let span_start = p.prev_token.span;
|
|
|
|
|
2024-12-04 04:55:06 +00:00
|
|
|
p.expect(exp!(OpenParen))?;
|
|
|
|
|
|
|
|
while !p.eat(exp!(CloseParen)) {
|
|
|
|
const OPTIONS: [(ExpKeywordPair, ast::InlineAsmOptions); ast::InlineAsmOptions::COUNT] = [
|
|
|
|
(exp!(Pure), ast::InlineAsmOptions::PURE),
|
|
|
|
(exp!(Nomem), ast::InlineAsmOptions::NOMEM),
|
|
|
|
(exp!(Readonly), ast::InlineAsmOptions::READONLY),
|
|
|
|
(exp!(PreservesFlags), ast::InlineAsmOptions::PRESERVES_FLAGS),
|
|
|
|
(exp!(Noreturn), ast::InlineAsmOptions::NORETURN),
|
|
|
|
(exp!(Nostack), ast::InlineAsmOptions::NOSTACK),
|
|
|
|
(exp!(MayUnwind), ast::InlineAsmOptions::MAY_UNWIND),
|
|
|
|
(exp!(AttSyntax), ast::InlineAsmOptions::ATT_SYNTAX),
|
|
|
|
(exp!(Raw), ast::InlineAsmOptions::RAW),
|
2024-07-25 08:05:31 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
'blk: {
|
2024-12-04 04:55:06 +00:00
|
|
|
for (exp, option) in OPTIONS {
|
2024-08-04 14:42:37 +00:00
|
|
|
let kw_matched = if asm_macro.is_supported_option(option) {
|
2024-12-04 04:55:06 +00:00
|
|
|
p.eat_keyword(exp)
|
2024-08-04 14:42:37 +00:00
|
|
|
} else {
|
2024-12-04 04:55:06 +00:00
|
|
|
p.eat_keyword_noexpect(exp.kw)
|
2024-08-04 14:42:37 +00:00
|
|
|
};
|
2024-07-25 22:08:22 +00:00
|
|
|
|
|
|
|
if kw_matched {
|
2024-12-04 04:55:06 +00:00
|
|
|
try_set_option(p, args, asm_macro, exp.kw, option);
|
2024-07-25 08:05:31 +00:00
|
|
|
break 'blk;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-05 21:21:03 +00:00
|
|
|
return p.unexpected();
|
2020-03-19 07:41:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Allow trailing commas
|
2024-12-04 04:55:06 +00:00
|
|
|
if p.eat(exp!(CloseParen)) {
|
2020-03-19 07:41:43 +00:00
|
|
|
break;
|
|
|
|
}
|
2024-12-04 04:55:06 +00:00
|
|
|
p.expect(exp!(Comma))?;
|
2020-03-19 07:41:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let new_span = span_start.to(p.prev_token.span);
|
2020-06-12 18:31:41 +00:00
|
|
|
args.options_spans.push(new_span);
|
2020-03-19 07:41:43 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-01-27 09:44:25 +00:00
|
|
|
fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, ()> {
|
2021-07-29 11:43:26 +00:00
|
|
|
let span_start = p.prev_token.span;
|
|
|
|
|
2024-12-04 04:55:06 +00:00
|
|
|
p.expect(exp!(OpenParen))?;
|
2021-07-29 11:43:26 +00:00
|
|
|
|
2024-12-04 04:55:06 +00:00
|
|
|
if p.eat(exp!(CloseParen)) {
|
2024-06-18 09:43:28 +00:00
|
|
|
return Err(p.dcx().create_err(errors::NonABI { span: p.token.span }));
|
2021-10-14 07:23:09 +00:00
|
|
|
}
|
2021-07-29 11:43:26 +00:00
|
|
|
|
2021-10-14 07:23:09 +00:00
|
|
|
let mut new_abis = Vec::new();
|
2024-12-04 04:55:06 +00:00
|
|
|
while !p.eat(exp!(CloseParen)) {
|
2021-10-14 07:23:09 +00:00
|
|
|
match p.parse_str_lit() {
|
|
|
|
Ok(str_lit) => {
|
|
|
|
new_abis.push((str_lit.symbol_unescaped, str_lit.span));
|
|
|
|
}
|
|
|
|
Err(opt_lit) => {
|
|
|
|
let span = opt_lit.map_or(p.token.span, |lit| lit.span);
|
2024-06-25 10:04:21 +00:00
|
|
|
return Err(p.dcx().create_err(errors::AsmExpectedStringLiteral { span }));
|
2021-10-14 07:23:09 +00:00
|
|
|
}
|
|
|
|
};
|
2021-07-29 11:43:26 +00:00
|
|
|
|
2021-10-14 07:23:09 +00:00
|
|
|
// Allow trailing commas
|
2024-12-04 04:55:06 +00:00
|
|
|
if p.eat(exp!(CloseParen)) {
|
2021-10-14 07:23:09 +00:00
|
|
|
break;
|
|
|
|
}
|
2024-12-04 04:55:06 +00:00
|
|
|
p.expect(exp!(Comma))?;
|
2021-10-14 07:23:09 +00:00
|
|
|
}
|
2021-07-29 11:43:26 +00:00
|
|
|
|
2021-10-14 07:23:09 +00:00
|
|
|
let full_span = span_start.to(p.prev_token.span);
|
|
|
|
|
|
|
|
match &new_abis[..] {
|
|
|
|
// should have errored above during parsing
|
|
|
|
[] => unreachable!(),
|
|
|
|
[(abi, _span)] => args.clobber_abis.push((*abi, full_span)),
|
2023-07-23 08:50:14 +00:00
|
|
|
abis => {
|
2021-10-14 07:23:09 +00:00
|
|
|
for (abi, span) in abis {
|
|
|
|
args.clobber_abis.push((*abi, *span));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-07-29 11:43:26 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-03-19 07:41:43 +00:00
|
|
|
fn parse_reg<'a>(
|
|
|
|
p: &mut Parser<'a>,
|
|
|
|
explicit_reg: &mut bool,
|
2022-01-27 09:44:25 +00:00
|
|
|
) -> PResult<'a, ast::InlineAsmRegOrRegClass> {
|
2024-12-04 04:55:06 +00:00
|
|
|
p.expect(exp!(OpenParen))?;
|
2020-09-27 16:47:52 +00:00
|
|
|
let result = match p.token.uninterpolate().kind {
|
2024-02-13 23:28:27 +00:00
|
|
|
token::Ident(name, IdentIsRaw::No) => ast::InlineAsmRegOrRegClass::RegClass(name),
|
2020-03-19 07:41:43 +00:00
|
|
|
token::Literal(token::Lit { kind: token::LitKind::Str, symbol, suffix: _ }) => {
|
|
|
|
*explicit_reg = true;
|
|
|
|
ast::InlineAsmRegOrRegClass::Reg(symbol)
|
|
|
|
}
|
|
|
|
_ => {
|
2023-12-18 10:14:02 +00:00
|
|
|
return Err(p.dcx().create_err(errors::ExpectedRegisterClassOrExplicitRegister {
|
2023-06-21 11:01:53 +00:00
|
|
|
span: p.token.span,
|
|
|
|
}));
|
2020-03-19 07:41:43 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
p.bump();
|
2024-12-04 04:55:06 +00:00
|
|
|
p.expect(exp!(CloseParen))?;
|
2020-03-19 07:41:43 +00:00
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
|
2024-02-25 21:22:11 +00:00
|
|
|
fn expand_preparsed_asm(
|
|
|
|
ecx: &mut ExtCtxt<'_>,
|
2024-09-05 11:45:26 +00:00
|
|
|
asm_macro: AsmMacro,
|
2024-02-25 21:22:11 +00:00
|
|
|
args: AsmArgs,
|
2024-03-12 02:55:17 +00:00
|
|
|
) -> ExpandResult<Result<ast::InlineAsm, ErrorGuaranteed>, ()> {
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
let mut template = vec![];
|
2020-02-12 15:47:43 +00:00
|
|
|
// 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()];
|
2023-05-02 15:42:36 +00:00
|
|
|
for pos in args.reg_args.iter() {
|
|
|
|
used[pos] = true;
|
2020-02-12 15:47:43 +00:00
|
|
|
}
|
2020-06-11 00:27:48 +00:00
|
|
|
let named_pos: FxHashMap<usize, Symbol> =
|
|
|
|
args.named_args.iter().map(|(&sym, &idx)| (idx, sym)).collect();
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
let mut line_spans = Vec::with_capacity(args.templates.len());
|
|
|
|
let mut curarg = 0;
|
|
|
|
|
2021-08-19 20:34:01 +00:00
|
|
|
let mut template_strs = Vec::with_capacity(args.templates.len());
|
|
|
|
|
2022-07-12 20:54:47 +00:00
|
|
|
for (i, template_expr) in args.templates.into_iter().enumerate() {
|
|
|
|
if i != 0 {
|
2024-06-24 15:17:59 +00:00
|
|
|
template.push(ast::InlineAsmTemplatePiece::String("\n".into()));
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let msg = "asm template must be a string literal";
|
|
|
|
let template_sp = template_expr.span;
|
2024-09-27 04:19:15 +00:00
|
|
|
let template_is_mac_call = matches!(template_expr.kind, ast::ExprKind::MacCall(_));
|
2024-12-31 04:15:40 +00:00
|
|
|
let ExprToSpannedString {
|
|
|
|
symbol: template_str,
|
|
|
|
style: template_style,
|
|
|
|
span: template_span,
|
2024-12-31 05:03:22 +00:00
|
|
|
..
|
2024-12-31 04:15:40 +00:00
|
|
|
} = {
|
2024-03-12 02:55:17 +00:00
|
|
|
let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, template_expr, msg) else {
|
|
|
|
return ExpandResult::Retry(());
|
|
|
|
};
|
|
|
|
match mac {
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
Ok(template_part) => template_part,
|
|
|
|
Err(err) => {
|
2024-03-12 02:55:17 +00:00
|
|
|
return ExpandResult::Ready(Err(match err {
|
2024-02-25 21:22:11 +00:00
|
|
|
Ok((err, _)) => err.emit(),
|
|
|
|
Err(guar) => guar,
|
2024-03-12 02:55:17 +00:00
|
|
|
}));
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
}
|
2024-03-12 02:55:17 +00:00
|
|
|
}
|
|
|
|
};
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
|
|
|
|
let str_style = match template_style {
|
|
|
|
ast::StrStyle::Cooked => None,
|
|
|
|
ast::StrStyle::Raw(raw) => Some(raw as usize),
|
|
|
|
};
|
|
|
|
|
|
|
|
let template_snippet = ecx.source_map().span_to_snippet(template_sp).ok();
|
2021-08-19 20:34:01 +00:00
|
|
|
template_strs.push((
|
|
|
|
template_str,
|
2022-11-16 21:58:58 +00:00
|
|
|
template_snippet.as_deref().map(Symbol::intern),
|
2021-08-19 20:34:01 +00:00
|
|
|
template_sp,
|
|
|
|
));
|
2021-12-15 03:39:23 +00:00
|
|
|
let template_str = template_str.as_str();
|
2021-02-20 06:17:18 +00:00
|
|
|
|
2021-03-24 04:52:57 +00:00
|
|
|
if let Some(InlineAsmArch::X86 | InlineAsmArch::X86_64) = ecx.sess.asm_arch {
|
|
|
|
let find_span = |needle: &str| -> Span {
|
|
|
|
if let Some(snippet) = &template_snippet {
|
|
|
|
if let Some(pos) = snippet.find(needle) {
|
|
|
|
let end = pos
|
2021-11-07 09:33:27 +00:00
|
|
|
+ snippet[pos..]
|
2021-03-24 04:52:57 +00:00
|
|
|
.find(|c| matches!(c, '\n' | ';' | '\\' | '"'))
|
|
|
|
.unwrap_or(snippet[pos..].len() - 1);
|
|
|
|
let inner = InnerSpan::new(pos, end);
|
|
|
|
return template_sp.from_inner(inner);
|
2021-02-20 06:17:18 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-24 04:52:57 +00:00
|
|
|
template_sp
|
|
|
|
};
|
2021-02-20 06:17:18 +00:00
|
|
|
|
2021-03-24 04:52:57 +00:00
|
|
|
if template_str.contains(".intel_syntax") {
|
2024-05-20 17:47:54 +00:00
|
|
|
ecx.psess().buffer_lint(
|
2021-03-24 04:52:57 +00:00
|
|
|
lint::builtin::BAD_ASM_STYLE,
|
|
|
|
find_span(".intel_syntax"),
|
2021-07-14 23:24:12 +00:00
|
|
|
ecx.current_expansion.lint_node_id,
|
2024-04-14 20:11:14 +00:00
|
|
|
BuiltinLintDiag::AvoidUsingIntelSyntax,
|
2021-03-24 04:52:57 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
if template_str.contains(".att_syntax") {
|
2024-05-20 17:47:54 +00:00
|
|
|
ecx.psess().buffer_lint(
|
2021-03-24 04:52:57 +00:00
|
|
|
lint::builtin::BAD_ASM_STYLE,
|
|
|
|
find_span(".att_syntax"),
|
2021-07-14 23:24:12 +00:00
|
|
|
ecx.current_expansion.lint_node_id,
|
2024-04-14 20:11:14 +00:00
|
|
|
BuiltinLintDiag::AvoidUsingAttSyntax,
|
2021-03-24 04:52:57 +00:00
|
|
|
);
|
2021-02-20 06:17:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-24 15:25:44 +00:00
|
|
|
// Don't treat raw asm as a format string.
|
|
|
|
if args.options.contains(ast::InlineAsmOptions::RAW) {
|
2024-06-24 15:17:59 +00:00
|
|
|
template.push(ast::InlineAsmTemplatePiece::String(template_str.to_string().into()));
|
2021-06-24 15:25:44 +00:00
|
|
|
let template_num_lines = 1 + template_str.matches('\n').count();
|
|
|
|
line_spans.extend(std::iter::repeat(template_sp).take(template_num_lines));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
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);
|
2024-09-27 04:19:15 +00:00
|
|
|
let err_sp = if template_is_mac_call {
|
|
|
|
// If the template is a macro call we can't reliably point to the error's
|
|
|
|
// span so just use the template's span as the error span (fixes #129503)
|
|
|
|
template_span
|
|
|
|
} else {
|
|
|
|
template_span.from_inner(InnerSpan::new(err.span.start, err.span.end))
|
|
|
|
};
|
|
|
|
|
2023-05-16 06:04:03 +00:00
|
|
|
let msg = format!("invalid asm template string: {}", err.description);
|
2023-12-18 09:54:03 +00:00
|
|
|
let mut e = ecx.dcx().struct_span_err(err_sp, msg);
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
e.span_label(err_sp, err.label + " in asm template string");
|
|
|
|
if let Some(note) = err.note {
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 03:26:58 +00:00
|
|
|
e.note(note);
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
}
|
|
|
|
if let Some((label, span)) = err.secondary_label {
|
2022-04-29 16:48:58 +00:00
|
|
|
let err_sp = template_span.from_inner(InnerSpan::new(span.start, span.end));
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
e.span_label(err_sp, label);
|
2020-05-06 13:46:01 +00:00
|
|
|
}
|
2024-02-25 21:22:11 +00:00
|
|
|
let guar = e.emit();
|
2024-03-12 02:55:17 +00:00
|
|
|
return ExpandResult::Ready(Err(guar));
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
curarg = parser.curarg;
|
|
|
|
|
2022-04-29 16:48:58 +00:00
|
|
|
let mut arg_spans = parser
|
|
|
|
.arg_places
|
|
|
|
.iter()
|
|
|
|
.map(|span| template_span.from_inner(InnerSpan::new(span.start, span.end)));
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
for piece in unverified_pieces {
|
|
|
|
match piece {
|
2025-01-23 09:16:08 +00:00
|
|
|
parse::Piece::Lit(s) => {
|
2024-06-24 15:17:59 +00:00
|
|
|
template.push(ast::InlineAsmTemplatePiece::String(s.to_string().into()))
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
}
|
|
|
|
parse::Piece::NextArgument(arg) => {
|
|
|
|
let span = arg_spans.next().unwrap_or(template_sp);
|
|
|
|
|
|
|
|
let operand_idx = match arg.position {
|
2022-07-31 15:11:00 +00:00
|
|
|
parse::ArgumentIs(idx) | parse::ArgumentImplicitlyIs(idx) => {
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
if idx >= args.operands.len()
|
|
|
|
|| named_pos.contains_key(&idx)
|
2023-05-02 15:42:36 +00:00
|
|
|
|| args.reg_args.contains(idx)
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
{
|
2023-07-25 20:00:13 +00:00
|
|
|
let msg = format!("invalid reference to argument at index {idx}");
|
2023-12-18 09:54:03 +00:00
|
|
|
let mut err = ecx.dcx().struct_span_err(span, msg);
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
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 {
|
2023-07-25 20:00:13 +00:00
|
|
|
0 => format!("no {positional}arguments were given"),
|
|
|
|
1 => format!("there is 1 {positional}argument"),
|
|
|
|
x => format!("there are {x} {positional}arguments"),
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
};
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 03:26:58 +00:00
|
|
|
err.note(msg);
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
|
|
|
|
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",
|
|
|
|
);
|
2023-05-02 15:42:36 +00:00
|
|
|
} else if args.reg_args.contains(idx) {
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
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",
|
|
|
|
);
|
2022-12-16 04:20:34 +00:00
|
|
|
err.span_help(
|
|
|
|
args.operands[idx].1,
|
|
|
|
"use the register name directly in the assembly code",
|
|
|
|
);
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
}
|
|
|
|
err.emit();
|
|
|
|
None
|
2020-02-12 15:47:43 +00:00
|
|
|
} else {
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
Some(idx)
|
2020-02-12 15:47:43 +00:00
|
|
|
}
|
|
|
|
}
|
2022-07-31 15:11:00 +00:00
|
|
|
parse::ArgumentNamed(name) => {
|
2022-04-29 16:48:58 +00:00
|
|
|
match args.named_args.get(&Symbol::intern(name)) {
|
|
|
|
Some(&idx) => Some(idx),
|
|
|
|
None => {
|
2022-07-31 15:11:00 +00:00
|
|
|
let span = arg.position_span;
|
2023-12-18 09:54:03 +00:00
|
|
|
ecx.dcx()
|
2024-06-25 10:04:21 +00:00
|
|
|
.create_err(errors::AsmNoMatchedArgumentName {
|
|
|
|
name: name.to_owned(),
|
|
|
|
span: template_span
|
2023-12-18 09:54:03 +00:00
|
|
|
.from_inner(InnerSpan::new(span.start, span.end)),
|
2024-06-25 10:04:21 +00:00
|
|
|
})
|
2023-12-18 09:54:03 +00:00
|
|
|
.emit();
|
2022-04-29 16:48:58 +00:00
|
|
|
None
|
|
|
|
}
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
}
|
2022-04-29 16:48:58 +00:00
|
|
|
}
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let mut chars = arg.format.ty.chars();
|
|
|
|
let mut modifier = chars.next();
|
|
|
|
if chars.next().is_some() {
|
|
|
|
let span = arg
|
|
|
|
.format
|
|
|
|
.ty_span
|
2022-04-29 16:48:58 +00:00
|
|
|
.map(|sp| template_sp.from_inner(InnerSpan::new(sp.start, sp.end)))
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
.unwrap_or(template_sp);
|
2023-12-18 09:54:03 +00:00
|
|
|
ecx.dcx().emit_err(errors::AsmModifierInvalid { span });
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
modifier = None;
|
|
|
|
}
|
2020-02-12 15:47:43 +00:00
|
|
|
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
if let Some(operand_idx) = operand_idx {
|
|
|
|
used[operand_idx] = true;
|
|
|
|
template.push(ast::InlineAsmTemplatePiece::Placeholder {
|
|
|
|
operand_idx,
|
|
|
|
modifier,
|
|
|
|
span,
|
|
|
|
});
|
|
|
|
}
|
2020-02-12 15:47:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
|
|
|
|
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 {
|
2022-04-29 16:48:58 +00:00
|
|
|
line_spans.extend(
|
|
|
|
parser
|
|
|
|
.line_spans
|
|
|
|
.iter()
|
|
|
|
.map(|span| template_span.from_inner(InnerSpan::new(span.start, span.end))),
|
|
|
|
);
|
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.
2020-06-15 06:33:55 +00:00
|
|
|
};
|
2020-02-12 15:47:43 +00:00
|
|
|
}
|
|
|
|
|
2020-06-11 00:27:48 +00:00
|
|
|
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"
|
2020-02-12 15:47:43 +00:00
|
|
|
} else {
|
2020-06-11 00:27:48 +00:00
|
|
|
help_str.push_str(&format!(" {{{}}}", idx));
|
|
|
|
"argument never used"
|
|
|
|
};
|
|
|
|
unused_operands.push((args.operands[idx].1, msg));
|
|
|
|
}
|
|
|
|
}
|
2024-08-07 10:41:49 +00:00
|
|
|
match unused_operands[..] {
|
|
|
|
[] => {}
|
|
|
|
[(sp, msg)] => {
|
2024-01-03 06:03:10 +00:00
|
|
|
ecx.dcx()
|
|
|
|
.struct_span_err(sp, msg)
|
2024-01-08 22:08:49 +00:00
|
|
|
.with_span_label(sp, msg)
|
|
|
|
.with_help(format!(
|
2024-01-03 06:03:10 +00:00
|
|
|
"if this argument is intentionally unused, \
|
|
|
|
consider using it in an asm comment: `\"/*{help_str} */\"`"
|
|
|
|
))
|
|
|
|
.emit();
|
2020-02-12 15:47:43 +00:00
|
|
|
}
|
|
|
|
_ => {
|
2023-12-18 09:54:03 +00:00
|
|
|
let mut err = ecx.dcx().struct_span_err(
|
2020-02-12 15:47:43 +00:00
|
|
|
unused_operands.iter().map(|&(sp, _)| sp).collect::<Vec<Span>>(),
|
|
|
|
"multiple unused asm arguments",
|
|
|
|
);
|
|
|
|
for (sp, msg) in unused_operands {
|
|
|
|
err.span_label(sp, msg);
|
|
|
|
}
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 03:26:58 +00:00
|
|
|
err.help(format!(
|
2020-06-11 00:27:48 +00:00
|
|
|
"if these arguments are intentionally unused, \
|
2023-07-25 20:00:13 +00:00
|
|
|
consider using them in an asm comment: `\"/*{help_str} */\"`"
|
2020-06-11 00:27:48 +00:00
|
|
|
));
|
2020-02-12 15:47:43 +00:00
|
|
|
err.emit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-12 02:55:17 +00:00
|
|
|
ExpandResult::Ready(Ok(ast::InlineAsm {
|
2024-09-10 12:42:17 +00:00
|
|
|
asm_macro,
|
2021-07-29 11:43:26 +00:00
|
|
|
template,
|
2021-08-19 20:34:01 +00:00
|
|
|
template_strs: template_strs.into_boxed_slice(),
|
2021-07-29 11:43:26 +00:00
|
|
|
operands: args.operands,
|
2021-10-14 07:23:09 +00:00
|
|
|
clobber_abis: args.clobber_abis,
|
2021-07-29 11:43:26 +00:00
|
|
|
options: args.options,
|
|
|
|
line_spans,
|
2024-03-12 02:55:17 +00:00
|
|
|
}))
|
2020-02-12 15:47:43 +00:00
|
|
|
}
|
|
|
|
|
2021-12-21 04:05:17 +00:00
|
|
|
pub(super) fn expand_asm<'cx>(
|
2020-02-12 15:47:43 +00:00
|
|
|
ecx: &'cx mut ExtCtxt<'_>,
|
|
|
|
sp: Span,
|
|
|
|
tts: TokenStream,
|
2024-03-12 02:55:17 +00:00
|
|
|
) -> MacroExpanderResult<'cx> {
|
2024-08-04 14:42:37 +00:00
|
|
|
ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::Asm) {
|
2021-04-11 19:51:28 +00:00
|
|
|
Ok(args) => {
|
2024-09-10 12:42:17 +00:00
|
|
|
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::Asm, args) else {
|
2024-03-12 02:55:17 +00:00
|
|
|
return ExpandResult::Retry(());
|
|
|
|
};
|
|
|
|
let expr = match mac {
|
2024-02-25 21:22:11 +00:00
|
|
|
Ok(inline_asm) => P(ast::Expr {
|
2021-04-11 19:51:28 +00:00
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
kind: ast::ExprKind::InlineAsm(P(inline_asm)),
|
|
|
|
span: sp,
|
|
|
|
attrs: ast::AttrVec::new(),
|
|
|
|
tokens: None,
|
2024-02-25 21:22:11 +00:00
|
|
|
}),
|
|
|
|
Err(guar) => DummyResult::raw_expr(sp, Some(guar)),
|
2021-04-11 19:51:28 +00:00
|
|
|
};
|
|
|
|
MacEager::expr(expr)
|
|
|
|
}
|
Make `DiagnosticBuilder::emit` consuming.
This works for most of its call sites. This is nice, because `emit` very
much makes sense as a consuming operation -- indeed,
`DiagnosticBuilderState` exists to ensure no diagnostic is emitted
twice, but it uses runtime checks.
For the small number of call sites where a consuming emit doesn't work,
the commit adds `DiagnosticBuilder::emit_without_consuming`. (This will
be removed in subsequent commits.)
Likewise, `emit_unless` becomes consuming. And `delay_as_bug` becomes
consuming, while `delay_as_bug_without_consuming` is added (which will
also be removed in subsequent commits.)
All this requires significant changes to `DiagnosticBuilder`'s chaining
methods. Currently `DiagnosticBuilder` method chaining uses a
non-consuming `&mut self -> &mut Self` style, which allows chaining to
be used when the chain ends in `emit()`, like so:
```
struct_err(msg).span(span).emit();
```
But it doesn't work when producing a `DiagnosticBuilder` value,
requiring this:
```
let mut err = self.struct_err(msg);
err.span(span);
err
```
This style of chaining won't work with consuming `emit` though. For
that, we need to use to a `self -> Self` style. That also would allow
`DiagnosticBuilder` production to be chained, e.g.:
```
self.struct_err(msg).span(span)
```
However, removing the `&mut self -> &mut Self` style would require that
individual modifications of a `DiagnosticBuilder` go from this:
```
err.span(span);
```
to this:
```
err = err.span(span);
```
There are *many* such places. I have a high tolerance for tedious
refactorings, but even I gave up after a long time trying to convert
them all.
Instead, this commit has it both ways: the existing `&mut self -> Self`
chaining methods are kept, and new `self -> Self` chaining methods are
added, all of which have a `_mv` suffix (short for "move"). Changes to
the existing `forward!` macro lets this happen with very little
additional boilerplate code. I chose to add the suffix to the new
chaining methods rather than the existing ones, because the number of
changes required is much smaller that way.
This doubled chainging is a bit clumsy, but I think it is worthwhile
because it allows a *lot* of good things to subsequently happen. In this
commit, there are many `mut` qualifiers removed in places where
diagnostics are emitted without being modified. In subsequent commits:
- chaining can be used more, making the code more concise;
- more use of chaining also permits the removal of redundant diagnostic
APIs like `struct_err_with_code`, which can be replaced easily with
`struct_err` + `code_mv`;
- `emit_without_diagnostic` can be removed, which simplifies a lot of
machinery, removing the need for `DiagnosticBuilderState`.
2024-01-03 01:17:35 +00:00
|
|
|
Err(err) => {
|
2024-02-25 21:22:11 +00:00
|
|
|
let guar = err.emit();
|
|
|
|
DummyResult::any(sp, guar)
|
2021-04-11 19:51:28 +00:00
|
|
|
}
|
2024-03-12 02:55:17 +00:00
|
|
|
})
|
2021-04-11 19:51:28 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 10:47:40 +00:00
|
|
|
pub(super) fn expand_naked_asm<'cx>(
|
|
|
|
ecx: &'cx mut ExtCtxt<'_>,
|
|
|
|
sp: Span,
|
|
|
|
tts: TokenStream,
|
|
|
|
) -> MacroExpanderResult<'cx> {
|
2024-09-05 11:45:26 +00:00
|
|
|
ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::NakedAsm) {
|
2024-09-09 10:47:40 +00:00
|
|
|
Ok(args) => {
|
2024-09-10 12:42:17 +00:00
|
|
|
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::NakedAsm, args)
|
|
|
|
else {
|
2024-09-09 10:47:40 +00:00
|
|
|
return ExpandResult::Retry(());
|
|
|
|
};
|
|
|
|
let expr = match mac {
|
2024-09-05 17:45:40 +00:00
|
|
|
Ok(inline_asm) => P(ast::Expr {
|
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
kind: ast::ExprKind::InlineAsm(P(inline_asm)),
|
|
|
|
span: sp,
|
|
|
|
attrs: ast::AttrVec::new(),
|
|
|
|
tokens: None,
|
|
|
|
}),
|
2024-09-09 10:47:40 +00:00
|
|
|
Err(guar) => DummyResult::raw_expr(sp, Some(guar)),
|
|
|
|
};
|
|
|
|
MacEager::expr(expr)
|
|
|
|
}
|
|
|
|
Err(err) => {
|
|
|
|
let guar = err.emit();
|
|
|
|
DummyResult::any(sp, guar)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-12-21 04:05:17 +00:00
|
|
|
pub(super) fn expand_global_asm<'cx>(
|
2021-04-11 19:51:28 +00:00
|
|
|
ecx: &'cx mut ExtCtxt<'_>,
|
|
|
|
sp: Span,
|
|
|
|
tts: TokenStream,
|
2024-03-12 02:55:17 +00:00
|
|
|
) -> MacroExpanderResult<'cx> {
|
2024-08-04 14:42:37 +00:00
|
|
|
ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::GlobalAsm) {
|
2024-03-12 02:55:17 +00:00
|
|
|
Ok(args) => {
|
2024-09-10 12:42:17 +00:00
|
|
|
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::GlobalAsm, args)
|
|
|
|
else {
|
2024-03-12 02:55:17 +00:00
|
|
|
return ExpandResult::Retry(());
|
|
|
|
};
|
|
|
|
match mac {
|
|
|
|
Ok(inline_asm) => MacEager::items(smallvec![P(ast::Item {
|
|
|
|
attrs: ast::AttrVec::new(),
|
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)),
|
|
|
|
vis: ast::Visibility {
|
|
|
|
span: sp.shrink_to_lo(),
|
|
|
|
kind: ast::VisibilityKind::Inherited,
|
|
|
|
tokens: None,
|
|
|
|
},
|
|
|
|
span: sp,
|
2021-04-11 19:51:28 +00:00
|
|
|
tokens: None,
|
2024-03-12 02:55:17 +00:00
|
|
|
})]),
|
|
|
|
Err(guar) => DummyResult::any(sp, guar),
|
|
|
|
}
|
|
|
|
}
|
Make `DiagnosticBuilder::emit` consuming.
This works for most of its call sites. This is nice, because `emit` very
much makes sense as a consuming operation -- indeed,
`DiagnosticBuilderState` exists to ensure no diagnostic is emitted
twice, but it uses runtime checks.
For the small number of call sites where a consuming emit doesn't work,
the commit adds `DiagnosticBuilder::emit_without_consuming`. (This will
be removed in subsequent commits.)
Likewise, `emit_unless` becomes consuming. And `delay_as_bug` becomes
consuming, while `delay_as_bug_without_consuming` is added (which will
also be removed in subsequent commits.)
All this requires significant changes to `DiagnosticBuilder`'s chaining
methods. Currently `DiagnosticBuilder` method chaining uses a
non-consuming `&mut self -> &mut Self` style, which allows chaining to
be used when the chain ends in `emit()`, like so:
```
struct_err(msg).span(span).emit();
```
But it doesn't work when producing a `DiagnosticBuilder` value,
requiring this:
```
let mut err = self.struct_err(msg);
err.span(span);
err
```
This style of chaining won't work with consuming `emit` though. For
that, we need to use to a `self -> Self` style. That also would allow
`DiagnosticBuilder` production to be chained, e.g.:
```
self.struct_err(msg).span(span)
```
However, removing the `&mut self -> &mut Self` style would require that
individual modifications of a `DiagnosticBuilder` go from this:
```
err.span(span);
```
to this:
```
err = err.span(span);
```
There are *many* such places. I have a high tolerance for tedious
refactorings, but even I gave up after a long time trying to convert
them all.
Instead, this commit has it both ways: the existing `&mut self -> Self`
chaining methods are kept, and new `self -> Self` chaining methods are
added, all of which have a `_mv` suffix (short for "move"). Changes to
the existing `forward!` macro lets this happen with very little
additional boilerplate code. I chose to add the suffix to the new
chaining methods rather than the existing ones, because the number of
changes required is much smaller that way.
This doubled chainging is a bit clumsy, but I think it is worthwhile
because it allows a *lot* of good things to subsequently happen. In this
commit, there are many `mut` qualifiers removed in places where
diagnostics are emitted without being modified. In subsequent commits:
- chaining can be used more, making the code more concise;
- more use of chaining also permits the removal of redundant diagnostic
APIs like `struct_err_with_code`, which can be replaced easily with
`struct_err` + `code_mv`;
- `emit_without_diagnostic` can be removed, which simplifies a lot of
machinery, removing the need for `DiagnosticBuilderState`.
2024-01-03 01:17:35 +00:00
|
|
|
Err(err) => {
|
2024-02-25 21:22:11 +00:00
|
|
|
let guar = err.emit();
|
|
|
|
DummyResult::any(sp, guar)
|
2020-02-12 15:47:43 +00:00
|
|
|
}
|
2024-03-12 02:55:17 +00:00
|
|
|
})
|
2020-02-12 15:47:43 +00:00
|
|
|
}
|