@@ -18,6 +18,21 @@ use {rustc_ast as ast, rustc_parse_format as parse};
1818use crate :: errors;
1919use crate :: util:: { ExprToSpannedString , expr_to_spanned_string} ;
2020
21+ pub struct RawAsmArgs ( Vec < RawAsmArg > ) ;
22+
23+ pub struct RawAsmArg {
24+ pub span : Span ,
25+ pub attributes : ast:: AttrVec ,
26+ pub kind : RawAsmArgKind ,
27+ }
28+
29+ enum RawAsmArgKind {
30+ Template ( P < ast:: Expr > ) ,
31+ Operand ( Option < Symbol > , ast:: InlineAsmOperand ) ,
32+ Options ( Vec < ( Symbol , ast:: InlineAsmOptions , Span , Span ) > ) ,
33+ ClobberAbi ( Vec < ( Symbol , Span ) > ) ,
34+ }
35+
2136pub struct AsmArgs {
2237 pub templates : Vec < P < ast:: Expr > > ,
2338 pub operands : Vec < ( ast:: InlineAsmOperand , Span ) > ,
@@ -139,31 +154,28 @@ fn parse_asm_operand<'a>(
139154 } ) )
140155}
141156
142- // Primarily public for rustfmt consumption.
143- // Internal consumers should continue to leverage `expand_asm`/`expand__global_asm`
144- pub fn parse_asm_args < ' a > (
157+ pub fn parse_raw_asm_args < ' a > (
145158 p : & mut Parser < ' a > ,
146159 sp : Span ,
147160 asm_macro : AsmMacro ,
148- ) -> PResult < ' a , AsmArgs > {
161+ ) -> PResult < ' a , Vec < RawAsmArg > > {
149162 let dcx = p. dcx ( ) ;
150163
151164 if p. token == token:: Eof {
152165 return Err ( dcx. create_err ( errors:: AsmRequiresTemplate { span : sp } ) ) ;
153166 }
154167
168+ let mut args = Vec :: new ( ) ;
169+
155170 let first_template = p. parse_expr ( ) ?;
156- let mut args = AsmArgs {
157- templates : vec ! [ first_template] ,
158- operands : vec ! [ ] ,
159- named_args : Default :: default ( ) ,
160- reg_args : Default :: default ( ) ,
161- clobber_abis : Vec :: new ( ) ,
162- options : ast:: InlineAsmOptions :: empty ( ) ,
163- options_spans : vec ! [ ] ,
164- } ;
171+ args. push ( RawAsmArg {
172+ span : first_template. span ,
173+ attributes : ast:: AttrVec :: new ( ) ,
174+ kind : RawAsmArgKind :: Template ( first_template) ,
175+ } ) ;
165176
166177 let mut allow_templates = true ;
178+
167179 while p. token != token:: Eof {
168180 if !p. eat ( exp ! ( Comma ) ) {
169181 if allow_templates {
@@ -178,22 +190,116 @@ pub fn parse_asm_args<'a>(
178190 break ;
179191 } // accept trailing commas
180192
193+ let span_start = p. token . span ;
194+
181195 // Parse clobber_abi
182196 if p. eat_keyword ( exp ! ( ClobberAbi ) ) {
183- parse_clobber_abi ( p, & mut args) ?;
184197 allow_templates = false ;
198+
199+ p. expect ( exp ! ( OpenParen ) ) ?;
200+
201+ // FIXME: why not allow this?
202+ if p. eat ( exp ! ( CloseParen ) ) {
203+ return Err ( p. dcx ( ) . create_err ( errors:: NonABI { span : p. token . span } ) ) ;
204+ }
205+
206+ let mut new_abis = Vec :: new ( ) ;
207+ while !p. eat ( exp ! ( CloseParen ) ) {
208+ match p. parse_str_lit ( ) {
209+ Ok ( str_lit) => {
210+ new_abis. push ( ( str_lit. symbol_unescaped , str_lit. span ) ) ;
211+ }
212+ Err ( opt_lit) => {
213+ let span = opt_lit. map_or ( p. token . span , |lit| lit. span ) ;
214+ return Err ( p. dcx ( ) . create_err ( errors:: AsmExpectedStringLiteral { span } ) ) ;
215+ }
216+ } ;
217+
218+ // Allow trailing commas
219+ if p. eat ( exp ! ( CloseParen ) ) {
220+ break ;
221+ }
222+ p. expect ( exp ! ( Comma ) ) ?;
223+ }
224+
225+ args. push ( RawAsmArg {
226+ span : span_start. to ( p. prev_token . span ) ,
227+ attributes : ast:: AttrVec :: new ( ) ,
228+ kind : RawAsmArgKind :: ClobberAbi ( new_abis) ,
229+ } ) ;
230+
185231 continue ;
186232 }
187233
188234 // Parse options
189235 if p. eat_keyword ( exp ! ( Options ) ) {
190- parse_options ( p, & mut args, asm_macro) ?;
191236 allow_templates = false ;
237+
238+ p. expect ( exp ! ( OpenParen ) ) ?;
239+
240+ let mut options = Vec :: new ( ) ;
241+
242+ while !p. eat ( exp ! ( CloseParen ) ) {
243+ const OPTIONS : [ ( ExpKeywordPair , ast:: InlineAsmOptions ) ;
244+ ast:: InlineAsmOptions :: COUNT ] = [
245+ ( exp ! ( Pure ) , ast:: InlineAsmOptions :: PURE ) ,
246+ ( exp ! ( Nomem ) , ast:: InlineAsmOptions :: NOMEM ) ,
247+ ( exp ! ( Readonly ) , ast:: InlineAsmOptions :: READONLY ) ,
248+ ( exp ! ( PreservesFlags ) , ast:: InlineAsmOptions :: PRESERVES_FLAGS ) ,
249+ ( exp ! ( Noreturn ) , ast:: InlineAsmOptions :: NORETURN ) ,
250+ ( exp ! ( Nostack ) , ast:: InlineAsmOptions :: NOSTACK ) ,
251+ ( exp ! ( MayUnwind ) , ast:: InlineAsmOptions :: MAY_UNWIND ) ,
252+ ( exp ! ( AttSyntax ) , ast:: InlineAsmOptions :: ATT_SYNTAX ) ,
253+ ( exp ! ( Raw ) , ast:: InlineAsmOptions :: RAW ) ,
254+ ] ;
255+
256+ ' blk: {
257+ for ( exp, option) in OPTIONS {
258+ let kw_matched = if asm_macro. is_supported_option ( option) {
259+ p. eat_keyword ( exp)
260+ } else {
261+ p. eat_keyword_noexpect ( exp. kw )
262+ } ;
263+
264+ if kw_matched {
265+ let span = p. prev_token . span ;
266+ let full_span =
267+ if p. token == token:: Comma { span. to ( p. token . span ) } else { span } ;
268+
269+ if !asm_macro. is_supported_option ( option) {
270+ // Tool-only output
271+ p. dcx ( ) . emit_err ( errors:: AsmUnsupportedOption {
272+ span,
273+ symbol : exp. kw ,
274+ full_span,
275+ macro_name : asm_macro. macro_name ( ) ,
276+ } ) ;
277+ }
278+
279+ options. push ( ( exp. kw , option, span, full_span) ) ;
280+ break ' blk;
281+ }
282+ }
283+
284+ return p. unexpected_any ( ) ;
285+ }
286+
287+ // Allow trailing commas
288+ if p. eat ( exp ! ( CloseParen ) ) {
289+ break ;
290+ }
291+ p. expect ( exp ! ( Comma ) ) ?;
292+ }
293+
294+ args. push ( RawAsmArg {
295+ span : span_start. to ( p. prev_token . span ) ,
296+ attributes : ast:: AttrVec :: new ( ) ,
297+ kind : RawAsmArgKind :: Options ( options) ,
298+ } ) ;
299+
192300 continue ;
193301 }
194302
195- let span_start = p. token . span ;
196-
197303 // Parse operand names
198304 let name = if p. token . is_ident ( ) && p. look_ahead ( 1 , |t| * t == token:: Eq ) {
199305 let ( ident, _) = p. token . ident ( ) . unwrap ( ) ;
@@ -225,40 +331,143 @@ pub fn parse_asm_args<'a>(
225331 return Err ( err) ;
226332 }
227333 }
228- args. templates . push ( template) ;
334+
335+ args. push ( RawAsmArg {
336+ span : template. span ,
337+ attributes : ast:: AttrVec :: new ( ) ,
338+ kind : RawAsmArgKind :: Template ( template) ,
339+ } ) ;
340+
229341 continue ;
230342 } else {
231343 p. unexpected_any ( ) ?
232344 }
233345 } ;
234346
235- let explicit_reg = matches ! ( op. reg( ) , Some ( ast:: InlineAsmRegOrRegClass :: Reg ( _) ) ) ;
236-
237347 allow_templates = false ;
238- let span = span_start. to ( p. prev_token . span ) ;
239- let slot = args. operands . len ( ) ;
240- args. operands . push ( ( op, span) ) ;
241348
242- // Validate the order of named, positional & explicit register operands and
243- // clobber_abi/options. We do this at the end once we have the full span
244- // of the argument available.
349+ args. push ( RawAsmArg {
350+ span : span_start. to ( p. prev_token . span ) ,
351+ attributes : ast:: AttrVec :: new ( ) ,
352+ kind : RawAsmArgKind :: Operand ( name, op) ,
353+ } ) ;
354+ }
355+
356+ Ok ( args)
357+ }
358+
359+ pub fn parse_asm_args < ' a > (
360+ p : & mut Parser < ' a > ,
361+ sp : Span ,
362+ asm_macro : AsmMacro ,
363+ ) -> PResult < ' a , AsmArgs > {
364+ let dcx = p. dcx ( ) ;
365+
366+ let mut args = AsmArgs {
367+ templates : vec ! [ ] ,
368+ operands : vec ! [ ] ,
369+ named_args : Default :: default ( ) ,
370+ reg_args : Default :: default ( ) ,
371+ clobber_abis : Vec :: new ( ) ,
372+ options : ast:: InlineAsmOptions :: empty ( ) ,
373+ options_spans : vec ! [ ] ,
374+ } ;
245375
246- if explicit_reg {
247- if name. is_some ( ) {
248- dcx. emit_err ( errors:: AsmExplicitRegisterName { span } ) ;
376+ let mut allow_templates = true ;
377+
378+ for arg in parse_raw_asm_args ( p, sp, asm_macro) ? {
379+ match arg. kind {
380+ RawAsmArgKind :: Template ( template) => {
381+ if allow_templates {
382+ args. templates . push ( template) ;
383+ } else {
384+ match template. kind {
385+ ast:: ExprKind :: Lit ( token_lit)
386+ if matches ! (
387+ token_lit. kind,
388+ token:: LitKind :: Str | token:: LitKind :: StrRaw ( _)
389+ ) => { }
390+ ast:: ExprKind :: MacCall ( ..) => { }
391+ _ => {
392+ let err = dcx. create_err ( errors:: AsmExpectedOther {
393+ span : template. span ,
394+ is_inline_asm : matches ! ( asm_macro, AsmMacro :: Asm ) ,
395+ } ) ;
396+ return Err ( err) ;
397+ }
398+ }
399+ args. templates . push ( template) ;
400+ }
249401 }
250- args. reg_args . insert ( slot) ;
251- } else if let Some ( name) = name {
252- if let Some ( & prev) = args. named_args . get ( & name) {
253- dcx. emit_err ( errors:: AsmDuplicateArg { span, name, prev : args. operands [ prev] . 1 } ) ;
254- continue ;
402+ RawAsmArgKind :: Operand ( name, op) => {
403+ allow_templates = false ;
404+
405+ let explicit_reg = matches ! ( op. reg( ) , Some ( ast:: InlineAsmRegOrRegClass :: Reg ( _) ) ) ;
406+
407+ let span = arg. span ;
408+ let slot = args. operands . len ( ) ;
409+ args. operands . push ( ( op, span) ) ;
410+
411+ // Validate the order of named, positional & explicit register operands and
412+ // clobber_abi/options. We do this at the end once we have the full span
413+ // of the argument available.
414+
415+ if explicit_reg {
416+ if name. is_some ( ) {
417+ dcx. emit_err ( errors:: AsmExplicitRegisterName { span } ) ;
418+ }
419+ args. reg_args . insert ( slot) ;
420+ } else if let Some ( name) = name {
421+ if let Some ( & prev) = args. named_args . get ( & name) {
422+ dcx. emit_err ( errors:: AsmDuplicateArg {
423+ span,
424+ name,
425+ prev : args. operands [ prev] . 1 ,
426+ } ) ;
427+ continue ;
428+ }
429+ args. named_args . insert ( name, slot) ;
430+ } else if !args. named_args . is_empty ( ) || !args. reg_args . is_empty ( ) {
431+ let named = args. named_args . values ( ) . map ( |p| args. operands [ * p] . 1 ) . collect ( ) ;
432+ let explicit = args. reg_args . iter ( ) . map ( |p| args. operands [ p] . 1 ) . collect ( ) ;
433+
434+ dcx. emit_err ( errors:: AsmPositionalAfter { span, named, explicit } ) ;
435+ }
255436 }
256- args. named_args . insert ( name, slot) ;
257- } else if !args. named_args . is_empty ( ) || !args. reg_args . is_empty ( ) {
258- let named = args. named_args . values ( ) . map ( |p| args. operands [ * p] . 1 ) . collect ( ) ;
259- let explicit = args. reg_args . iter ( ) . map ( |p| args. operands [ p] . 1 ) . collect ( ) ;
437+ RawAsmArgKind :: Options ( new_options) => {
438+ allow_templates = false ;
439+
440+ for ( symbol, option, span, full_span) in new_options {
441+ if !asm_macro. is_supported_option ( option) {
442+ /*
443+ // Tool-only output
444+ p.dcx().emit_err(errors::AsmUnsupportedOption {
445+ span,
446+ symbol,
447+ full_span,
448+ macro_name: asm_macro.macro_name(),
449+ });
450+ */
451+ } else if args. options . contains ( option) {
452+ // Tool-only output
453+ p. dcx ( ) . emit_err ( errors:: AsmOptAlreadyprovided { span, symbol, full_span } ) ;
454+ } else {
455+ args. options |= option;
456+ }
457+ }
260458
261- dcx. emit_err ( errors:: AsmPositionalAfter { span, named, explicit } ) ;
459+ args. options_spans . push ( arg. span ) ;
460+ }
461+ RawAsmArgKind :: ClobberAbi ( new_abis) => {
462+ allow_templates = false ;
463+
464+ match & new_abis[ ..] {
465+ // should have errored above during parsing
466+ [ ] => unreachable ! ( ) ,
467+ [ ( abi, _span) ] => args. clobber_abis . push ( ( * abi, arg. span ) ) ,
468+ _ => args. clobber_abis . extend ( new_abis) ,
469+ }
470+ }
262471 }
263472 }
264473
0 commit comments