@@ -4,7 +4,7 @@ use rustc_ast::ptr::P;
44use rustc_ast:: tokenstream:: TokenStream ;
55use rustc_ast:: { AsmMacro , token} ;
66use rustc_data_structures:: fx:: { FxHashMap , FxIndexMap } ;
7- use rustc_errors:: PResult ;
7+ use rustc_errors:: { DiagCtxtHandle , PResult } ;
88use rustc_expand:: base:: * ;
99use rustc_index:: bit_set:: GrowableBitSet ;
1010use rustc_parse:: exp;
@@ -18,10 +18,11 @@ use {rustc_ast as ast, rustc_parse_format as parse};
1818use crate :: errors;
1919use crate :: util:: { ExprToSpannedString , expr_to_spanned_string} ;
2020
21+ /// An argument to one of the `asm!` macros. The argument is syntactically valid, but is otherwise
22+ /// not validated at all.
2123pub struct RawAsmArg {
22- pub span : Span ,
23- pub attributes : ast:: AttrVec ,
2424 pub kind : RawAsmArgKind ,
25+ pub span : Span ,
2526}
2627
2728pub enum RawAsmArgKind {
@@ -31,6 +32,7 @@ pub enum RawAsmArgKind {
3132 ClobberAbi ( Vec < ( Symbol , Span ) > ) ,
3233}
3334
35+ /// Validated assembly arguments, ready for macro expansion.
3436pub struct AsmArgs {
3537 pub templates : Vec < P < ast:: Expr > > ,
3638 pub operands : Vec < ( ast:: InlineAsmOperand , Span ) > ,
@@ -72,16 +74,6 @@ fn eat_operand_keyword<'a>(
7274 }
7375}
7476
75- fn parse_args < ' a > (
76- ecx : & ExtCtxt < ' a > ,
77- sp : Span ,
78- tts : TokenStream ,
79- asm_macro : AsmMacro ,
80- ) -> PResult < ' a , AsmArgs > {
81- let mut p = ecx. new_parser_from_tts ( tts) ;
82- parse_asm_args ( & mut p, sp, asm_macro)
83- }
84-
8577fn parse_asm_operand < ' a > (
8678 p : & mut Parser < ' a > ,
8779 asm_macro : AsmMacro ,
@@ -168,7 +160,6 @@ pub fn parse_raw_asm_args<'a>(
168160 let first_template = p. parse_expr ( ) ?;
169161 args. push ( RawAsmArg {
170162 span : first_template. span ,
171- attributes : ast:: AttrVec :: new ( ) ,
172163 kind : RawAsmArgKind :: Template ( first_template) ,
173164 } ) ;
174165
@@ -195,7 +186,6 @@ pub fn parse_raw_asm_args<'a>(
195186 allow_templates = false ;
196187
197188 args. push ( RawAsmArg {
198- attributes : ast:: AttrVec :: new ( ) ,
199189 kind : RawAsmArgKind :: ClobberAbi ( parse_clobber_abi ( p) ?) ,
200190 span : span_start. to ( p. prev_token . span ) ,
201191 } ) ;
@@ -208,7 +198,6 @@ pub fn parse_raw_asm_args<'a>(
208198 allow_templates = false ;
209199
210200 args. push ( RawAsmArg {
211- attributes : ast:: AttrVec :: new ( ) ,
212201 kind : RawAsmArgKind :: Options ( parse_options ( p, asm_macro) ?) ,
213202 span : span_start. to ( p. prev_token . span ) ,
214203 } ) ;
@@ -227,58 +216,68 @@ pub fn parse_raw_asm_args<'a>(
227216 None
228217 } ;
229218
230- let Some ( op) = parse_asm_operand ( p, asm_macro) ? else {
231- if allow_templates {
232- let template = p. parse_expr ( ) ?;
233- // If it can't possibly expand to a string, provide diagnostics here to include other
234- // things it could have been.
235- match template. kind {
236- ast:: ExprKind :: Lit ( token_lit)
237- if matches ! (
238- token_lit. kind,
239- token:: LitKind :: Str | token:: LitKind :: StrRaw ( _)
240- ) => { }
241- ast:: ExprKind :: MacCall ( ..) => { }
242- _ => {
243- let err = dcx. create_err ( errors:: AsmExpectedOther {
244- span : template. span ,
245- is_inline_asm : matches ! ( asm_macro, AsmMacro :: Asm ) ,
246- } ) ;
247- return Err ( err) ;
248- }
249- }
250-
251- args. push ( RawAsmArg {
252- span : template. span ,
253- attributes : ast:: AttrVec :: new ( ) ,
254- kind : RawAsmArgKind :: Template ( template) ,
255- } ) ;
219+ if let Some ( op) = parse_asm_operand ( p, asm_macro) ? {
220+ allow_templates = false ;
256221
257- continue ;
258- } else {
259- p. unexpected_any ( ) ?
222+ args. push ( RawAsmArg {
223+ span : span_start. to ( p. prev_token . span ) ,
224+ kind : RawAsmArgKind :: Operand ( name, op) ,
225+ } ) ;
226+ } else if allow_templates {
227+ let template = p. parse_expr ( ) ?;
228+ // If it can't possibly expand to a string, provide diagnostics here to include other
229+ // things it could have been.
230+ match template. kind {
231+ ast:: ExprKind :: Lit ( token_lit)
232+ if matches ! (
233+ token_lit. kind,
234+ token:: LitKind :: Str | token:: LitKind :: StrRaw ( _)
235+ ) => { }
236+ ast:: ExprKind :: MacCall ( ..) => { }
237+ _ => {
238+ let err = dcx. create_err ( errors:: AsmExpectedOther {
239+ span : template. span ,
240+ is_inline_asm : matches ! ( asm_macro, AsmMacro :: Asm ) ,
241+ } ) ;
242+ return Err ( err) ;
243+ }
260244 }
261- } ;
262245
263- allow_templates = false ;
264-
265- args. push ( RawAsmArg {
266- span : span_start. to ( p. prev_token . span ) ,
267- attributes : ast:: AttrVec :: new ( ) ,
268- kind : RawAsmArgKind :: Operand ( name, op) ,
269- } ) ;
246+ args. push ( RawAsmArg { span : template. span , kind : RawAsmArgKind :: Template ( template) } ) ;
247+ } else {
248+ p. unexpected_any ( ) ?
249+ }
270250 }
271251
272252 Ok ( args)
273253}
274254
255+ fn parse_args < ' a > (
256+ ecx : & ExtCtxt < ' a > ,
257+ sp : Span ,
258+ tts : TokenStream ,
259+ asm_macro : AsmMacro ,
260+ ) -> PResult < ' a , AsmArgs > {
261+ let mut p = ecx. new_parser_from_tts ( tts) ;
262+ parse_asm_args ( & mut p, sp, asm_macro)
263+ }
264+
265+ // public for use in rustfmt
266+ // FIXME: use `RawAsmArg` in the formatting code instead.
275267pub fn parse_asm_args < ' a > (
276268 p : & mut Parser < ' a > ,
277269 sp : Span ,
278270 asm_macro : AsmMacro ,
279271) -> PResult < ' a , AsmArgs > {
280- let dcx = p. dcx ( ) ;
272+ let raw_args = parse_raw_asm_args ( p, sp, asm_macro) ?;
273+ validate_raw_asm_args ( p. dcx ( ) , asm_macro, raw_args)
274+ }
281275
276+ pub fn validate_raw_asm_args < ' a > (
277+ dcx : DiagCtxtHandle < ' a > ,
278+ asm_macro : AsmMacro ,
279+ raw_args : Vec < RawAsmArg > ,
280+ ) -> PResult < ' a , AsmArgs > {
282281 let mut args = AsmArgs {
283282 templates : vec ! [ ] ,
284283 operands : vec ! [ ] ,
@@ -291,12 +290,11 @@ pub fn parse_asm_args<'a>(
291290
292291 let mut allow_templates = true ;
293292
294- for arg in parse_raw_asm_args ( p , sp , asm_macro ) ? {
293+ for arg in raw_args {
295294 match arg. kind {
296295 RawAsmArgKind :: Template ( template) => {
297- if allow_templates {
298- args. templates . push ( template) ;
299- } else {
296+ // The error for the first template is delayed.
297+ if !allow_templates {
300298 match template. kind {
301299 ast:: ExprKind :: Lit ( token_lit)
302300 if matches ! (
@@ -312,14 +310,14 @@ pub fn parse_asm_args<'a>(
312310 return Err ( err) ;
313311 }
314312 }
315- args. templates . push ( template) ;
316313 }
314+
315+ args. templates . push ( template) ;
317316 }
318317 RawAsmArgKind :: Operand ( name, op) => {
319318 allow_templates = false ;
320319
321320 let explicit_reg = matches ! ( op. reg( ) , Some ( ast:: InlineAsmRegOrRegClass :: Reg ( _) ) ) ;
322-
323321 let span = arg. span ;
324322 let slot = args. operands . len ( ) ;
325323 args. operands . push ( ( op, span) ) ;
@@ -366,7 +364,7 @@ pub fn parse_asm_args<'a>(
366364 */
367365 } else if args. options . contains ( option) {
368366 // Tool-only output
369- p . dcx ( ) . emit_err ( errors:: AsmOptAlreadyprovided { span, symbol, full_span } ) ;
367+ dcx. emit_err ( errors:: AsmOptAlreadyprovided { span, symbol, full_span } ) ;
370368 } else {
371369 args. options |= option;
372370 }
@@ -496,6 +494,7 @@ fn parse_options<'a>(
496494
497495 ' blk: {
498496 for ( exp, option) in OPTIONS {
497+ // Gives a more accurate list of expected next tokens.
499498 let kw_matched = if asm_macro. is_supported_option ( option) {
500499 p. eat_keyword ( exp)
501500 } else {
@@ -538,7 +537,6 @@ fn parse_options<'a>(
538537fn parse_clobber_abi < ' a > ( p : & mut Parser < ' a > ) -> PResult < ' a , Vec < ( Symbol , Span ) > > {
539538 p. expect ( exp ! ( OpenParen ) ) ?;
540539
541- // FIXME: why not allow this?
542540 if p. eat ( exp ! ( CloseParen ) ) {
543541 return Err ( p. dcx ( ) . create_err ( errors:: NonABI { span : p. token . span } ) ) ;
544542 }
0 commit comments