@@ -36,37 +36,74 @@ pub struct AsmArgs {
36
36
/// - `Ok(true)` if the current token matches the keyword, and was expected
37
37
/// - `Ok(false)` if the current token does not match the keyword
38
38
/// - `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 ) {
41
45
Ok ( p. eat_keyword ( symbol) )
42
46
} else {
43
47
let span = p. token . span ;
44
48
if p. eat_keyword_noexpect ( symbol) {
45
49
// in gets printed as `r#in` otherwise
46
50
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
+ } ) )
48
56
} else {
49
57
Ok ( false )
50
58
}
51
59
}
52
60
}
53
61
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
+
54
91
fn parse_args < ' a > (
55
92
ecx : & ExtCtxt < ' a > ,
56
93
sp : Span ,
57
94
tts : TokenStream ,
58
- is_global_asm : bool ,
95
+ asm_macro : AsmMacro ,
59
96
) -> PResult < ' a , AsmArgs > {
60
97
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 )
62
99
}
63
100
64
101
// Primarily public for rustfmt consumption.
65
102
// Internal consumers should continue to leverage `expand_asm`/`expand__global_asm`
66
103
pub fn parse_asm_args < ' a > (
67
104
p : & mut Parser < ' a > ,
68
105
sp : Span ,
69
- is_global_asm : bool ,
106
+ asm_macro : AsmMacro ,
70
107
) -> PResult < ' a , AsmArgs > {
71
108
let dcx = p. dcx ( ) ;
72
109
@@ -109,7 +146,7 @@ pub fn parse_asm_args<'a>(
109
146
110
147
// Parse options
111
148
if p. eat_keyword ( sym:: options) {
112
- parse_options ( p, & mut args, is_global_asm ) ?;
149
+ parse_options ( p, & mut args, asm_macro ) ?;
113
150
allow_templates = false ;
114
151
continue ;
115
152
}
@@ -128,23 +165,23 @@ pub fn parse_asm_args<'a>(
128
165
} ;
129
166
130
167
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 ) ? {
132
169
let reg = parse_reg ( p, & mut explicit_reg) ?;
133
170
if p. eat_keyword ( kw:: Underscore ) {
134
171
let err = dcx. create_err ( errors:: AsmUnderscoreInput { span : p. token . span } ) ;
135
172
return Err ( err) ;
136
173
}
137
174
let expr = p. parse_expr ( ) ?;
138
175
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 ) ? {
140
177
let reg = parse_reg ( p, & mut explicit_reg) ?;
141
178
let expr = if p. eat_keyword ( kw:: Underscore ) { None } else { Some ( p. parse_expr ( ) ?) } ;
142
179
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 ) ? {
144
181
let reg = parse_reg ( p, & mut explicit_reg) ?;
145
182
let expr = if p. eat_keyword ( kw:: Underscore ) { None } else { Some ( p. parse_expr ( ) ?) } ;
146
183
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 ) ? {
148
185
let reg = parse_reg ( p, & mut explicit_reg) ?;
149
186
if p. eat_keyword ( kw:: Underscore ) {
150
187
let err = dcx. create_err ( errors:: AsmUnderscoreInput { span : p. token . span } ) ;
@@ -158,7 +195,7 @@ pub fn parse_asm_args<'a>(
158
195
} else {
159
196
ast:: InlineAsmOperand :: InOut { reg, expr, late : false }
160
197
}
161
- } else if eat_operand_keyword ( p, sym:: inlateout, !is_global_asm ) ? {
198
+ } else if eat_operand_keyword ( p, sym:: inlateout, asm_macro ) ? {
162
199
let reg = parse_reg ( p, & mut explicit_reg) ?;
163
200
if p. eat_keyword ( kw:: Underscore ) {
164
201
let err = dcx. create_err ( errors:: AsmUnderscoreInput { span : p. token . span } ) ;
@@ -172,7 +209,7 @@ pub fn parse_asm_args<'a>(
172
209
} else {
173
210
ast:: InlineAsmOperand :: InOut { reg, expr, late : true }
174
211
}
175
- } else if eat_operand_keyword ( p, sym:: label, !is_global_asm ) ? {
212
+ } else if eat_operand_keyword ( p, sym:: label, asm_macro ) ? {
176
213
let block = p. parse_block ( ) ?;
177
214
ast:: InlineAsmOperand :: Label { block }
178
215
} else if p. eat_keyword ( kw:: Const ) {
@@ -204,7 +241,7 @@ pub fn parse_asm_args<'a>(
204
241
_ => {
205
242
let err = dcx. create_err ( errors:: AsmExpectedOther {
206
243
span : template. span ,
207
- is_global_asm ,
244
+ is_inline_asm : matches ! ( asm_macro , AsmMacro :: Asm ) ,
208
245
} ) ;
209
246
return Err ( err) ;
210
247
}
@@ -302,20 +339,25 @@ pub fn parse_asm_args<'a>(
302
339
dcx. emit_err ( errors:: AsmMayUnwind { labels_sp } ) ;
303
340
}
304
341
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
+ } ) ;
310
349
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
+ }
319
361
}
320
362
}
321
363
@@ -336,10 +378,15 @@ fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
336
378
///
337
379
/// This function must be called immediately after the option token is parsed.
338
380
/// 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 ) {
340
382
// Tool-only output
341
383
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
+ } ) ;
343
390
}
344
391
345
392
/// Try to set the provided option in the provided `AsmArgs`.
@@ -350,12 +397,12 @@ fn err_unsupported_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
350
397
fn try_set_option < ' a > (
351
398
p : & Parser < ' a > ,
352
399
args : & mut AsmArgs ,
353
- is_global_asm : bool ,
400
+ asm_macro : AsmMacro ,
354
401
symbol : Symbol ,
355
402
option : ast:: InlineAsmOptions ,
356
403
) {
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 ) ;
359
406
} else if args. options . contains ( option) {
360
407
err_duplicate_option ( p, symbol, p. prev_token . span ) ;
361
408
} else {
@@ -366,7 +413,7 @@ fn try_set_option<'a>(
366
413
fn parse_options < ' a > (
367
414
p : & mut Parser < ' a > ,
368
415
args : & mut AsmArgs ,
369
- is_global_asm : bool ,
416
+ asm_macro : AsmMacro ,
370
417
) -> PResult < ' a , ( ) > {
371
418
let span_start = p. prev_token . span ;
372
419
@@ -387,15 +434,14 @@ fn parse_options<'a>(
387
434
388
435
' blk: {
389
436
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
+ } ;
396
442
397
443
if kw_matched {
398
- try_set_option ( p, args, is_global_asm , symbol, option) ;
444
+ try_set_option ( p, args, asm_macro , symbol, option) ;
399
445
break ' blk;
400
446
}
401
447
}
@@ -788,7 +834,7 @@ pub(super) fn expand_asm<'cx>(
788
834
sp : Span ,
789
835
tts : TokenStream ,
790
836
) -> MacroExpanderResult < ' cx > {
791
- ExpandResult :: Ready ( match parse_args ( ecx, sp, tts, false ) {
837
+ ExpandResult :: Ready ( match parse_args ( ecx, sp, tts, AsmMacro :: Asm ) {
792
838
Ok ( args) => {
793
839
let ExpandResult :: Ready ( mac) = expand_preparsed_asm ( ecx, args) else {
794
840
return ExpandResult :: Retry ( ( ) ) ;
@@ -817,7 +863,7 @@ pub(super) fn expand_global_asm<'cx>(
817
863
sp : Span ,
818
864
tts : TokenStream ,
819
865
) -> MacroExpanderResult < ' cx > {
820
- ExpandResult :: Ready ( match parse_args ( ecx, sp, tts, true ) {
866
+ ExpandResult :: Ready ( match parse_args ( ecx, sp, tts, AsmMacro :: GlobalAsm ) {
821
867
Ok ( args) => {
822
868
let ExpandResult :: Ready ( mac) = expand_preparsed_asm ( ecx, args) else {
823
869
return ExpandResult :: Retry ( ( ) ) ;
@@ -845,3 +891,32 @@ pub(super) fn expand_global_asm<'cx>(
845
891
}
846
892
} )
847
893
}
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