Skip to content

Commit dd0edd7

Browse files
committed
implement naked_asm macro
1 parent 739b1fd commit dd0edd7

File tree

7 files changed

+162
-68
lines changed

7 files changed

+162
-68
lines changed

compiler/rustc_builtin_macros/messages.ftl

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ builtin_macros_asm_duplicate_arg = duplicate argument named `{$name}`
1212
builtin_macros_asm_expected_comma = expected token: `,`
1313
.label = expected `,`
1414
15-
builtin_macros_asm_expected_other = expected operand, {$is_global_asm ->
16-
[true] options
17-
*[false] clobber_abi, options
15+
builtin_macros_asm_expected_other = expected operand, {$is_inline_asm ->
16+
[false] options
17+
*[true] clobber_abi, options
1818
}, or additional template string
1919
2020
builtin_macros_asm_expected_string_literal = expected string literal
@@ -51,6 +51,15 @@ builtin_macros_asm_sym_no_path = expected a path for argument to `sym`
5151
5252
builtin_macros_asm_underscore_input = _ cannot be used for input operands
5353
54+
builtin_macros_asm_unsupported_clobber_abi = `clobber_abi` cannot be used with `{$macro_name}!`
55+
56+
builtin_macros_asm_unsupported_operand = the `{$symbol}` operand cannot be used with `{$macro_name}!`
57+
.label = the `{$symbol}` operand is not meaningful for global-scoped inline assembly, remove it
58+
59+
builtin_macros_asm_unsupported_option = the `{$symbol}` option cannot be used with `{$macro_name}!`
60+
.label = the `{$symbol}` option is not meaningful for global-scoped inline assembly
61+
.suggestion = remove this option
62+
5463
builtin_macros_assert_missing_comma = unexpected string literal
5564
.suggestion = try adding a comma
5665
@@ -194,15 +203,6 @@ builtin_macros_format_unused_args = multiple unused formatting arguments
194203
195204
builtin_macros_format_use_positional = consider using a positional formatting argument instead
196205
197-
builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!`
198-
199-
builtin_macros_global_asm_unsupported_operand = the `{$symbol}` operand cannot be used with `global_asm!`
200-
.label = the `{$symbol}` operand is not meaningful for global-scoped inline assembly, remove it
201-
202-
builtin_macros_global_asm_unsupported_option = the `{$symbol}` option cannot be used with `global_asm!`
203-
.label = the `{$symbol}` option is not meaningful for global-scoped inline assembly
204-
.suggestion = remove this option
205-
206206
builtin_macros_invalid_crate_attribute = invalid crate attribute
207207
208208
builtin_macros_multiple_default_attrs = multiple `#[default]` attributes

compiler/rustc_builtin_macros/src/asm.rs

Lines changed: 117 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -36,37 +36,74 @@ pub struct AsmArgs {
3636
/// - `Ok(true)` if the current token matches the keyword, and was expected
3737
/// - `Ok(false)` if the current token does not match the keyword
3838
/// - `Err(_)` if the current token matches the keyword, but was not expected
39-
fn eat_operand_keyword<'a>(p: &mut Parser<'a>, symbol: Symbol, expect: bool) -> PResult<'a, bool> {
40-
if expect {
39+
fn eat_operand_keyword<'a>(
40+
p: &mut Parser<'a>,
41+
symbol: Symbol,
42+
asm_macro: AsmMacro,
43+
) -> PResult<'a, bool> {
44+
if matches!(asm_macro, AsmMacro::Asm) {
4145
Ok(p.eat_keyword(symbol))
4246
} else {
4347
let span = p.token.span;
4448
if p.eat_keyword_noexpect(symbol) {
4549
// in gets printed as `r#in` otherwise
4650
let symbol = if symbol == kw::In { "in" } else { symbol.as_str() };
47-
Err(p.dcx().create_err(errors::GlobalAsmUnsupportedOperand { span, symbol }))
51+
Err(p.dcx().create_err(errors::AsmUnsupportedOperand {
52+
span,
53+
symbol,
54+
macro_name: asm_macro.macro_name(),
55+
}))
4856
} else {
4957
Ok(false)
5058
}
5159
}
5260
}
5361

62+
// Public for rustfmt consumption.
63+
#[derive(Copy, Clone)]
64+
pub enum AsmMacro {
65+
/// The `asm!` macro
66+
Asm,
67+
/// The `global_asm!` macro
68+
GlobalAsm,
69+
/// The `naked_asm!` macro
70+
NakedAsm,
71+
}
72+
73+
impl AsmMacro {
74+
const fn macro_name(&self) -> &'static str {
75+
match self {
76+
AsmMacro::Asm => "asm",
77+
AsmMacro::GlobalAsm => "global_asm",
78+
AsmMacro::NakedAsm => "naked_asm",
79+
}
80+
}
81+
82+
const fn is_supported_option(&self, option: ast::InlineAsmOptions) -> bool {
83+
match self {
84+
AsmMacro::Asm => true,
85+
AsmMacro::GlobalAsm => ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option),
86+
AsmMacro::NakedAsm => ast::InlineAsmOptions::NAKED_OPTIONS.contains(option),
87+
}
88+
}
89+
}
90+
5491
fn parse_args<'a>(
5592
ecx: &ExtCtxt<'a>,
5693
sp: Span,
5794
tts: TokenStream,
58-
is_global_asm: bool,
95+
asm_macro: AsmMacro,
5996
) -> PResult<'a, AsmArgs> {
6097
let mut p = ecx.new_parser_from_tts(tts);
61-
parse_asm_args(&mut p, sp, is_global_asm)
98+
parse_asm_args(&mut p, sp, asm_macro)
6299
}
63100

64101
// Primarily public for rustfmt consumption.
65102
// Internal consumers should continue to leverage `expand_asm`/`expand__global_asm`
66103
pub fn parse_asm_args<'a>(
67104
p: &mut Parser<'a>,
68105
sp: Span,
69-
is_global_asm: bool,
106+
asm_macro: AsmMacro,
70107
) -> PResult<'a, AsmArgs> {
71108
let dcx = p.dcx();
72109

@@ -109,7 +146,7 @@ pub fn parse_asm_args<'a>(
109146

110147
// Parse options
111148
if p.eat_keyword(sym::options) {
112-
parse_options(p, &mut args, is_global_asm)?;
149+
parse_options(p, &mut args, asm_macro)?;
113150
allow_templates = false;
114151
continue;
115152
}
@@ -128,23 +165,23 @@ pub fn parse_asm_args<'a>(
128165
};
129166

130167
let mut explicit_reg = false;
131-
let op = if eat_operand_keyword(p, kw::In, !is_global_asm)? {
168+
let op = if eat_operand_keyword(p, kw::In, asm_macro)? {
132169
let reg = parse_reg(p, &mut explicit_reg)?;
133170
if p.eat_keyword(kw::Underscore) {
134171
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
135172
return Err(err);
136173
}
137174
let expr = p.parse_expr()?;
138175
ast::InlineAsmOperand::In { reg, expr }
139-
} else if eat_operand_keyword(p, sym::out, !is_global_asm)? {
176+
} else if eat_operand_keyword(p, sym::out, asm_macro)? {
140177
let reg = parse_reg(p, &mut explicit_reg)?;
141178
let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
142179
ast::InlineAsmOperand::Out { reg, expr, late: false }
143-
} else if eat_operand_keyword(p, sym::lateout, !is_global_asm)? {
180+
} else if eat_operand_keyword(p, sym::lateout, asm_macro)? {
144181
let reg = parse_reg(p, &mut explicit_reg)?;
145182
let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
146183
ast::InlineAsmOperand::Out { reg, expr, late: true }
147-
} else if eat_operand_keyword(p, sym::inout, !is_global_asm)? {
184+
} else if eat_operand_keyword(p, sym::inout, asm_macro)? {
148185
let reg = parse_reg(p, &mut explicit_reg)?;
149186
if p.eat_keyword(kw::Underscore) {
150187
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -158,7 +195,7 @@ pub fn parse_asm_args<'a>(
158195
} else {
159196
ast::InlineAsmOperand::InOut { reg, expr, late: false }
160197
}
161-
} else if eat_operand_keyword(p, sym::inlateout, !is_global_asm)? {
198+
} else if eat_operand_keyword(p, sym::inlateout, asm_macro)? {
162199
let reg = parse_reg(p, &mut explicit_reg)?;
163200
if p.eat_keyword(kw::Underscore) {
164201
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -172,7 +209,7 @@ pub fn parse_asm_args<'a>(
172209
} else {
173210
ast::InlineAsmOperand::InOut { reg, expr, late: true }
174211
}
175-
} else if eat_operand_keyword(p, sym::label, !is_global_asm)? {
212+
} else if eat_operand_keyword(p, sym::label, asm_macro)? {
176213
let block = p.parse_block()?;
177214
ast::InlineAsmOperand::Label { block }
178215
} else if p.eat_keyword(kw::Const) {
@@ -204,7 +241,7 @@ pub fn parse_asm_args<'a>(
204241
_ => {
205242
let err = dcx.create_err(errors::AsmExpectedOther {
206243
span: template.span,
207-
is_global_asm,
244+
is_inline_asm: matches!(asm_macro, AsmMacro::Asm),
208245
});
209246
return Err(err);
210247
}
@@ -302,20 +339,25 @@ pub fn parse_asm_args<'a>(
302339
dcx.emit_err(errors::AsmMayUnwind { labels_sp });
303340
}
304341

305-
if args.clobber_abis.len() > 0 {
306-
if is_global_asm {
307-
let err = dcx.create_err(errors::GlobalAsmClobberAbi {
308-
spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
309-
});
342+
if !args.clobber_abis.is_empty() {
343+
match asm_macro {
344+
AsmMacro::GlobalAsm | AsmMacro::NakedAsm => {
345+
let err = dcx.create_err(errors::AsmUnsupportedClobberAbi {
346+
spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
347+
macro_name: asm_macro.macro_name(),
348+
});
310349

311-
// Bail out now since this is likely to confuse later stages
312-
return Err(err);
313-
}
314-
if !regclass_outputs.is_empty() {
315-
dcx.emit_err(errors::AsmClobberNoReg {
316-
spans: regclass_outputs,
317-
clobbers: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
318-
});
350+
// Bail out now since this is likely to confuse later stages
351+
return Err(err);
352+
}
353+
AsmMacro::Asm => {
354+
if !regclass_outputs.is_empty() {
355+
dcx.emit_err(errors::AsmClobberNoReg {
356+
spans: regclass_outputs,
357+
clobbers: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
358+
});
359+
}
360+
}
319361
}
320362
}
321363

@@ -336,10 +378,15 @@ fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
336378
///
337379
/// This function must be called immediately after the option token is parsed.
338380
/// Otherwise, the suggestion will be incorrect.
339-
fn err_unsupported_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
381+
fn err_unsupported_option(p: &Parser<'_>, asm_macro: AsmMacro, symbol: Symbol, span: Span) {
340382
// Tool-only output
341383
let full_span = if p.token == token::Comma { span.to(p.token.span) } else { span };
342-
p.dcx().emit_err(errors::GlobalAsmUnsupportedOption { span, symbol, full_span });
384+
p.dcx().emit_err(errors::AsmUnsupportedOption {
385+
span,
386+
symbol,
387+
full_span,
388+
macro_name: asm_macro.macro_name(),
389+
});
343390
}
344391

345392
/// Try to set the provided option in the provided `AsmArgs`.
@@ -350,12 +397,12 @@ fn err_unsupported_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
350397
fn try_set_option<'a>(
351398
p: &Parser<'a>,
352399
args: &mut AsmArgs,
353-
is_global_asm: bool,
400+
asm_macro: AsmMacro,
354401
symbol: Symbol,
355402
option: ast::InlineAsmOptions,
356403
) {
357-
if is_global_asm && !ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option) {
358-
err_unsupported_option(p, symbol, p.prev_token.span);
404+
if !asm_macro.is_supported_option(option) {
405+
err_unsupported_option(p, asm_macro, symbol, p.prev_token.span);
359406
} else if args.options.contains(option) {
360407
err_duplicate_option(p, symbol, p.prev_token.span);
361408
} else {
@@ -366,7 +413,7 @@ fn try_set_option<'a>(
366413
fn parse_options<'a>(
367414
p: &mut Parser<'a>,
368415
args: &mut AsmArgs,
369-
is_global_asm: bool,
416+
asm_macro: AsmMacro,
370417
) -> PResult<'a, ()> {
371418
let span_start = p.prev_token.span;
372419

@@ -387,15 +434,14 @@ fn parse_options<'a>(
387434

388435
'blk: {
389436
for (symbol, option) in OPTIONS {
390-
let kw_matched =
391-
if !is_global_asm || ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option) {
392-
p.eat_keyword(symbol)
393-
} else {
394-
p.eat_keyword_noexpect(symbol)
395-
};
437+
let kw_matched = if asm_macro.is_supported_option(option) {
438+
p.eat_keyword(symbol)
439+
} else {
440+
p.eat_keyword_noexpect(symbol)
441+
};
396442

397443
if kw_matched {
398-
try_set_option(p, args, is_global_asm, symbol, option);
444+
try_set_option(p, args, asm_macro, symbol, option);
399445
break 'blk;
400446
}
401447
}
@@ -788,7 +834,7 @@ pub(super) fn expand_asm<'cx>(
788834
sp: Span,
789835
tts: TokenStream,
790836
) -> MacroExpanderResult<'cx> {
791-
ExpandResult::Ready(match parse_args(ecx, sp, tts, false) {
837+
ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::Asm) {
792838
Ok(args) => {
793839
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else {
794840
return ExpandResult::Retry(());
@@ -817,7 +863,7 @@ pub(super) fn expand_global_asm<'cx>(
817863
sp: Span,
818864
tts: TokenStream,
819865
) -> MacroExpanderResult<'cx> {
820-
ExpandResult::Ready(match parse_args(ecx, sp, tts, true) {
866+
ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::GlobalAsm) {
821867
Ok(args) => {
822868
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else {
823869
return ExpandResult::Retry(());
@@ -845,3 +891,32 @@ pub(super) fn expand_global_asm<'cx>(
845891
}
846892
})
847893
}
894+
895+
pub(super) fn expand_naked_asm<'cx>(
896+
ecx: &'cx mut ExtCtxt<'_>,
897+
sp: Span,
898+
tts: TokenStream,
899+
) -> MacroExpanderResult<'cx> {
900+
ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::NakedAsm) {
901+
Ok(args) => {
902+
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else {
903+
return ExpandResult::Retry(());
904+
};
905+
let expr = match mac {
906+
Ok(inline_asm) => P(ast::Expr {
907+
id: ast::DUMMY_NODE_ID,
908+
kind: ast::ExprKind::InlineAsm(P(inline_asm)),
909+
span: sp,
910+
attrs: ast::AttrVec::new(),
911+
tokens: None,
912+
}),
913+
Err(guar) => DummyResult::raw_expr(sp, Some(guar)),
914+
};
915+
MacEager::expr(expr)
916+
}
917+
Err(err) => {
918+
let guar = err.emit();
919+
DummyResult::any(sp, guar)
920+
}
921+
})
922+
}

0 commit comments

Comments
 (0)