@@ -19,6 +19,7 @@ struct AsmArgs {
19
19
operands : Vec < ( ast:: InlineAsmOperand , Span ) > ,
20
20
named_args : FxHashMap < Symbol , usize > ,
21
21
reg_args : FxHashSet < usize > ,
22
+ clobber_abi : Option < ( Symbol , Span ) > ,
22
23
options : ast:: InlineAsmOptions ,
23
24
options_spans : Vec < Span > ,
24
25
}
@@ -63,6 +64,7 @@ fn parse_args<'a>(
63
64
operands : vec ! [ ] ,
64
65
named_args : FxHashMap :: default ( ) ,
65
66
reg_args : FxHashSet :: default ( ) ,
67
+ clobber_abi : None ,
66
68
options : ast:: InlineAsmOptions :: empty ( ) ,
67
69
options_spans : vec ! [ ] ,
68
70
} ;
@@ -85,6 +87,13 @@ fn parse_args<'a>(
85
87
break ;
86
88
} // accept trailing commas
87
89
90
+ // Parse clobber_abi
91
+ if p. eat_keyword ( sym:: clobber_abi) {
92
+ parse_clobber_abi ( & mut p, & mut args) ?;
93
+ allow_templates = false ;
94
+ continue ;
95
+ }
96
+
88
97
// Parse options
89
98
if p. eat_keyword ( sym:: options) {
90
99
parse_options ( & mut p, & mut args, is_global_asm) ?;
@@ -160,7 +169,11 @@ fn parse_args<'a>(
160
169
ast:: ExprKind :: Lit ( ast:: Lit { kind : ast:: LitKind :: Str ( ..) , .. } ) => { }
161
170
ast:: ExprKind :: MacCall ( ..) => { }
162
171
_ => {
163
- let errstr = "expected operand, options, or additional template string" ;
172
+ let errstr = if is_global_asm {
173
+ "expected operand, options, or additional template string"
174
+ } else {
175
+ "expected operand, clobber_abi, options, or additional template string"
176
+ } ;
164
177
let mut err = ecx. struct_span_err ( template. span , errstr) ;
165
178
err. span_label ( template. span , errstr) ;
166
179
return Err ( err) ;
@@ -177,13 +190,19 @@ fn parse_args<'a>(
177
190
let slot = args. operands . len ( ) ;
178
191
args. operands . push ( ( op, span) ) ;
179
192
180
- // Validate the order of named, positional & explicit register operands and options. We do
181
- // this at the end once we have the full span of the argument available.
193
+ // Validate the order of named, positional & explicit register operands and
194
+ // clobber_abi/options. We do this at the end once we have the full span
195
+ // of the argument available.
182
196
if !args. options_spans . is_empty ( ) {
183
197
ecx. struct_span_err ( span, "arguments are not allowed after options" )
184
198
. span_labels ( args. options_spans . clone ( ) , "previous options" )
185
199
. span_label ( span, "argument" )
186
200
. emit ( ) ;
201
+ } else if let Some ( ( _, abi_span) ) = args. clobber_abi {
202
+ ecx. struct_span_err ( span, "arguments are not allowed after clobber_abi" )
203
+ . span_label ( abi_span, "clobber_abi" )
204
+ . span_label ( span, "argument" )
205
+ . emit ( ) ;
187
206
}
188
207
if explicit_reg {
189
208
if name. is_some ( ) {
@@ -256,16 +275,23 @@ fn parse_args<'a>(
256
275
257
276
let mut have_real_output = false ;
258
277
let mut outputs_sp = vec ! [ ] ;
278
+ let mut regclass_outputs = vec ! [ ] ;
259
279
for ( op, op_sp) in & args. operands {
260
280
match op {
261
- ast:: InlineAsmOperand :: Out { expr, .. }
262
- | ast:: InlineAsmOperand :: SplitInOut { out_expr : expr, .. } => {
281
+ ast:: InlineAsmOperand :: Out { reg , expr, .. }
282
+ | ast:: InlineAsmOperand :: SplitInOut { reg , out_expr : expr, .. } => {
263
283
outputs_sp. push ( * op_sp) ;
264
284
have_real_output |= expr. is_some ( ) ;
285
+ if let ast:: InlineAsmRegOrRegClass :: RegClass ( _) = reg {
286
+ regclass_outputs. push ( * op_sp) ;
287
+ }
265
288
}
266
- ast:: InlineAsmOperand :: InOut { .. } => {
289
+ ast:: InlineAsmOperand :: InOut { reg , .. } => {
267
290
outputs_sp. push ( * op_sp) ;
268
291
have_real_output = true ;
292
+ if let ast:: InlineAsmRegOrRegClass :: RegClass ( _) = reg {
293
+ regclass_outputs. push ( * op_sp) ;
294
+ }
269
295
}
270
296
_ => { }
271
297
}
@@ -284,6 +310,24 @@ fn parse_args<'a>(
284
310
// Bail out now since this is likely to confuse MIR
285
311
return Err ( err) ;
286
312
}
313
+ if let Some ( ( _, abi_span) ) = args. clobber_abi {
314
+ if is_global_asm {
315
+ let err =
316
+ ecx. struct_span_err ( abi_span, "`clobber_abi` cannot be used with `global_asm!`" ) ;
317
+
318
+ // Bail out now since this is likely to confuse later stages
319
+ return Err ( err) ;
320
+ }
321
+ if !regclass_outputs. is_empty ( ) {
322
+ ecx. struct_span_err (
323
+ regclass_outputs. clone ( ) ,
324
+ "asm with `clobber_abi` must specify explicit registers for outputs" ,
325
+ )
326
+ . span_label ( abi_span, "clobber_abi" )
327
+ . span_labels ( regclass_outputs, "generic outputs" )
328
+ . emit ( ) ;
329
+ }
330
+ }
287
331
288
332
Ok ( args)
289
333
}
@@ -375,6 +419,49 @@ fn parse_options<'a>(
375
419
Ok ( ( ) )
376
420
}
377
421
422
+ fn parse_clobber_abi < ' a > (
423
+ p : & mut Parser < ' a > ,
424
+ args : & mut AsmArgs ,
425
+ ) -> Result < ( ) , DiagnosticBuilder < ' a > > {
426
+ let span_start = p. prev_token . span ;
427
+
428
+ p. expect ( & token:: OpenDelim ( token:: DelimToken :: Paren ) ) ?;
429
+
430
+ let clobber_abi = match p. parse_str_lit ( ) {
431
+ Ok ( str_lit) => str_lit. symbol_unescaped ,
432
+ Err ( opt_lit) => {
433
+ let span = opt_lit. map_or ( p. token . span , |lit| lit. span ) ;
434
+ let mut err = p. sess . span_diagnostic . struct_span_err ( span, "expected string literal" ) ;
435
+ err. span_label ( span, "not a string literal" ) ;
436
+ return Err ( err) ;
437
+ }
438
+ } ;
439
+
440
+ p. expect ( & token:: CloseDelim ( token:: DelimToken :: Paren ) ) ?;
441
+
442
+ let new_span = span_start. to ( p. prev_token . span ) ;
443
+
444
+ if let Some ( ( _, prev_span) ) = args. clobber_abi {
445
+ let mut err = p
446
+ . sess
447
+ . span_diagnostic
448
+ . struct_span_err ( new_span, "clobber_abi specified multiple times" ) ;
449
+ err. span_label ( prev_span, "clobber_abi previously specified here" ) ;
450
+ return Err ( err) ;
451
+ } else if !args. options_spans . is_empty ( ) {
452
+ let mut err = p
453
+ . sess
454
+ . span_diagnostic
455
+ . struct_span_err ( new_span, "clobber_abi is not allowed after options" ) ;
456
+ err. span_labels ( args. options_spans . clone ( ) , "options" ) ;
457
+ return Err ( err) ;
458
+ }
459
+
460
+ args. clobber_abi = Some ( ( clobber_abi, new_span) ) ;
461
+
462
+ Ok ( ( ) )
463
+ }
464
+
378
465
fn parse_reg < ' a > (
379
466
p : & mut Parser < ' a > ,
380
467
explicit_reg : & mut bool ,
@@ -660,7 +747,13 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
660
747
}
661
748
}
662
749
663
- Some ( ast:: InlineAsm { template, operands : args. operands , options : args. options , line_spans } )
750
+ Some ( ast:: InlineAsm {
751
+ template,
752
+ operands : args. operands ,
753
+ clobber_abi : args. clobber_abi ,
754
+ options : args. options ,
755
+ line_spans,
756
+ } )
664
757
}
665
758
666
759
pub fn expand_asm < ' cx > (
0 commit comments