@@ -19,6 +19,7 @@ struct AsmArgs {
1919 operands : Vec < ( ast:: InlineAsmOperand , Span ) > ,
2020 named_args : FxHashMap < Symbol , usize > ,
2121 reg_args : FxHashSet < usize > ,
22+ clobber_abi : Option < ( Symbol , Span ) > ,
2223 options : ast:: InlineAsmOptions ,
2324 options_spans : Vec < Span > ,
2425}
@@ -63,6 +64,7 @@ fn parse_args<'a>(
6364 operands : vec ! [ ] ,
6465 named_args : FxHashMap :: default ( ) ,
6566 reg_args : FxHashSet :: default ( ) ,
67+ clobber_abi : None ,
6668 options : ast:: InlineAsmOptions :: empty ( ) ,
6769 options_spans : vec ! [ ] ,
6870 } ;
@@ -85,6 +87,13 @@ fn parse_args<'a>(
8587 break ;
8688 } // accept trailing commas
8789
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+
8897 // Parse options
8998 if p. eat_keyword ( sym:: options) {
9099 parse_options ( & mut p, & mut args, is_global_asm) ?;
@@ -160,7 +169,11 @@ fn parse_args<'a>(
160169 ast:: ExprKind :: Lit ( ast:: Lit { kind : ast:: LitKind :: Str ( ..) , .. } ) => { }
161170 ast:: ExprKind :: MacCall ( ..) => { }
162171 _ => {
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+ } ;
164177 let mut err = ecx. struct_span_err ( template. span , errstr) ;
165178 err. span_label ( template. span , errstr) ;
166179 return Err ( err) ;
@@ -177,13 +190,19 @@ fn parse_args<'a>(
177190 let slot = args. operands . len ( ) ;
178191 args. operands . push ( ( op, span) ) ;
179192
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.
182196 if !args. options_spans . is_empty ( ) {
183197 ecx. struct_span_err ( span, "arguments are not allowed after options" )
184198 . span_labels ( args. options_spans . clone ( ) , "previous options" )
185199 . span_label ( span, "argument" )
186200 . 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 ( ) ;
187206 }
188207 if explicit_reg {
189208 if name. is_some ( ) {
@@ -256,24 +275,31 @@ fn parse_args<'a>(
256275
257276 let mut have_real_output = false ;
258277 let mut outputs_sp = vec ! [ ] ;
278+ let mut regclass_outputs = vec ! [ ] ;
259279 for ( op, op_sp) in & args. operands {
260280 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, .. } => {
263283 outputs_sp. push ( * op_sp) ;
264284 have_real_output |= expr. is_some ( ) ;
285+ if let ast:: InlineAsmRegOrRegClass :: RegClass ( _) = reg {
286+ regclass_outputs. push ( * op_sp) ;
287+ }
265288 }
266- ast:: InlineAsmOperand :: InOut { .. } => {
289+ ast:: InlineAsmOperand :: InOut { reg , .. } => {
267290 outputs_sp. push ( * op_sp) ;
268291 have_real_output = true ;
292+ if let ast:: InlineAsmRegOrRegClass :: RegClass ( _) = reg {
293+ regclass_outputs. push ( * op_sp) ;
294+ }
269295 }
270296 _ => { }
271297 }
272298 }
273299 if args. options . contains ( ast:: InlineAsmOptions :: PURE ) && !have_real_output {
274300 ecx. struct_span_err (
275301 args. options_spans . clone ( ) ,
276- "asm with `pure` option must have at least one output" ,
302+ "asm with the `pure` option must have at least one output" ,
277303 )
278304 . emit ( ) ;
279305 }
@@ -284,6 +310,24 @@ fn parse_args<'a>(
284310 // Bail out now since this is likely to confuse MIR
285311 return Err ( err) ;
286312 }
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+ }
287331
288332 Ok ( args)
289333}
@@ -375,6 +419,49 @@ fn parse_options<'a>(
375419 Ok ( ( ) )
376420}
377421
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+
378465fn parse_reg < ' a > (
379466 p : & mut Parser < ' a > ,
380467 explicit_reg : & mut bool ,
@@ -730,7 +817,13 @@ fn expand_preparsed_asm(
730817 }
731818 }
732819
733- Some ( ast:: InlineAsm { template, operands : args. operands , options : args. options , line_spans } )
820+ Some ( ast:: InlineAsm {
821+ template,
822+ operands : args. operands ,
823+ clobber_abi : args. clobber_abi ,
824+ options : args. options ,
825+ line_spans,
826+ } )
734827}
735828
736829pub fn expand_asm < ' cx > (
0 commit comments