@@ -18,6 +18,21 @@ use {rustc_ast as ast, rustc_parse_format as parse};
18
18
use crate :: errors;
19
19
use crate :: util:: { ExprToSpannedString , expr_to_spanned_string} ;
20
20
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
+
21
36
pub struct AsmArgs {
22
37
pub templates : Vec < P < ast:: Expr > > ,
23
38
pub operands : Vec < ( ast:: InlineAsmOperand , Span ) > ,
@@ -139,31 +154,28 @@ fn parse_asm_operand<'a>(
139
154
} ) )
140
155
}
141
156
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 > (
145
158
p : & mut Parser < ' a > ,
146
159
sp : Span ,
147
160
asm_macro : AsmMacro ,
148
- ) -> PResult < ' a , AsmArgs > {
161
+ ) -> PResult < ' a , Vec < RawAsmArg > > {
149
162
let dcx = p. dcx ( ) ;
150
163
151
164
if p. token == token:: Eof {
152
165
return Err ( dcx. create_err ( errors:: AsmRequiresTemplate { span : sp } ) ) ;
153
166
}
154
167
168
+ let mut args = Vec :: new ( ) ;
169
+
155
170
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
+ } ) ;
165
176
166
177
let mut allow_templates = true ;
178
+
167
179
while p. token != token:: Eof {
168
180
if !p. eat ( exp ! ( Comma ) ) {
169
181
if allow_templates {
@@ -178,22 +190,116 @@ pub fn parse_asm_args<'a>(
178
190
break ;
179
191
} // accept trailing commas
180
192
193
+ let span_start = p. token . span ;
194
+
181
195
// Parse clobber_abi
182
196
if p. eat_keyword ( exp ! ( ClobberAbi ) ) {
183
- parse_clobber_abi ( p, & mut args) ?;
184
197
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
+
185
231
continue ;
186
232
}
187
233
188
234
// Parse options
189
235
if p. eat_keyword ( exp ! ( Options ) ) {
190
- parse_options ( p, & mut args, asm_macro) ?;
191
236
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
+
192
300
continue ;
193
301
}
194
302
195
- let span_start = p. token . span ;
196
-
197
303
// Parse operand names
198
304
let name = if p. token . is_ident ( ) && p. look_ahead ( 1 , |t| * t == token:: Eq ) {
199
305
let ( ident, _) = p. token . ident ( ) . unwrap ( ) ;
@@ -225,40 +331,143 @@ pub fn parse_asm_args<'a>(
225
331
return Err ( err) ;
226
332
}
227
333
}
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
+
229
341
continue ;
230
342
} else {
231
343
p. unexpected_any ( ) ?
232
344
}
233
345
} ;
234
346
235
- let explicit_reg = matches ! ( op. reg( ) , Some ( ast:: InlineAsmRegOrRegClass :: Reg ( _) ) ) ;
236
-
237
347
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) ) ;
241
348
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
+ } ;
245
375
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
+ }
249
401
}
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
+ }
255
436
}
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
+ }
260
458
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
+ }
262
471
}
263
472
}
264
473
0 commit comments