@@ -8,13 +8,14 @@ use rustc_expand::base::{self, *};
8
8
use rustc_parse:: parser:: Parser ;
9
9
use rustc_parse_format as parse;
10
10
use rustc_session:: lint;
11
+ use rustc_session:: parse:: ParseSess ;
11
12
use rustc_span:: symbol:: Ident ;
12
13
use rustc_span:: symbol:: { kw, sym, Symbol } ;
13
14
use rustc_span:: { InnerSpan , Span } ;
14
15
use rustc_target:: asm:: InlineAsmArch ;
15
16
use smallvec:: smallvec;
16
17
17
- struct AsmArgs {
18
+ pub struct AsmArgs {
18
19
templates : Vec < P < ast:: Expr > > ,
19
20
operands : Vec < ( ast:: InlineAsmOperand , Span ) > ,
20
21
named_args : FxHashMap < Symbol , usize > ,
@@ -31,15 +32,28 @@ fn parse_args<'a>(
31
32
is_global_asm : bool ,
32
33
) -> Result < AsmArgs , DiagnosticBuilder < ' a > > {
33
34
let mut p = ecx. new_parser_from_tts ( tts) ;
35
+ let sess = & ecx. sess . parse_sess ;
36
+ parse_asm_args ( & mut p, sess, sp, is_global_asm)
37
+ }
38
+
39
+ // Primarily public for rustfmt consumption.
40
+ // Internal consumers should continue to leverage `expand_asm`/`expand__global_asm`
41
+ pub fn parse_asm_args < ' a > (
42
+ p : & mut Parser < ' a > ,
43
+ sess : & ' a ParseSess ,
44
+ sp : Span ,
45
+ is_global_asm : bool ,
46
+ ) -> Result < AsmArgs , DiagnosticBuilder < ' a > > {
47
+ let diag = & sess. span_diagnostic ;
34
48
35
49
if p. token == token:: Eof {
36
- return Err ( ecx . struct_span_err ( sp, "requires at least a template string argument" ) ) ;
50
+ return Err ( diag . struct_span_err ( sp, "requires at least a template string argument" ) ) ;
37
51
}
38
52
39
53
// Detect use of the legacy llvm_asm! syntax (which used to be called asm!)
40
54
if !is_global_asm && p. look_ahead ( 1 , |t| * t == token:: Colon || * t == token:: ModSep ) {
41
55
let mut err =
42
- ecx . struct_span_err ( sp, "the legacy LLVM-style asm! syntax is no longer supported" ) ;
56
+ diag . struct_span_err ( sp, "the legacy LLVM-style asm! syntax is no longer supported" ) ;
43
57
err. note ( "consider migrating to the new asm! syntax specified in RFC 2873" ) ;
44
58
err. note ( "alternatively, switch to llvm_asm! to keep your code working as it is" ) ;
45
59
return Err ( err) ;
@@ -61,7 +75,7 @@ fn parse_args<'a>(
61
75
if !p. eat ( & token:: Comma ) {
62
76
if allow_templates {
63
77
// After a template string, we always expect *only* a comma...
64
- let mut err = ecx . struct_span_err ( p. token . span , "expected token: `,`" ) ;
78
+ let mut err = diag . struct_span_err ( p. token . span , "expected token: `,`" ) ;
65
79
err. span_label ( p. token . span , "expected `,`" ) ;
66
80
p. maybe_annotate_with_ascription ( & mut err, false ) ;
67
81
return Err ( err) ;
@@ -76,14 +90,14 @@ fn parse_args<'a>(
76
90
77
91
// Parse clobber_abi
78
92
if p. eat_keyword ( sym:: clobber_abi) {
79
- parse_clobber_abi ( & mut p, & mut args) ?;
93
+ parse_clobber_abi ( p, & mut args) ?;
80
94
allow_templates = false ;
81
95
continue ;
82
96
}
83
97
84
98
// Parse options
85
99
if p. eat_keyword ( sym:: options) {
86
- parse_options ( & mut p, & mut args, is_global_asm) ?;
100
+ parse_options ( p, & mut args, is_global_asm) ?;
87
101
allow_templates = false ;
88
102
continue ;
89
103
}
@@ -103,25 +117,25 @@ fn parse_args<'a>(
103
117
104
118
let mut explicit_reg = false ;
105
119
let op = if !is_global_asm && p. eat_keyword ( kw:: In ) {
106
- let reg = parse_reg ( & mut p, & mut explicit_reg) ?;
120
+ let reg = parse_reg ( p, & mut explicit_reg) ?;
107
121
if p. eat_keyword ( kw:: Underscore ) {
108
- let err = ecx . struct_span_err ( p. token . span , "_ cannot be used for input operands" ) ;
122
+ let err = diag . struct_span_err ( p. token . span , "_ cannot be used for input operands" ) ;
109
123
return Err ( err) ;
110
124
}
111
125
let expr = p. parse_expr ( ) ?;
112
126
ast:: InlineAsmOperand :: In { reg, expr }
113
127
} else if !is_global_asm && p. eat_keyword ( sym:: out) {
114
- let reg = parse_reg ( & mut p, & mut explicit_reg) ?;
128
+ let reg = parse_reg ( p, & mut explicit_reg) ?;
115
129
let expr = if p. eat_keyword ( kw:: Underscore ) { None } else { Some ( p. parse_expr ( ) ?) } ;
116
130
ast:: InlineAsmOperand :: Out { reg, expr, late : false }
117
131
} else if !is_global_asm && p. eat_keyword ( sym:: lateout) {
118
- let reg = parse_reg ( & mut p, & mut explicit_reg) ?;
132
+ let reg = parse_reg ( p, & mut explicit_reg) ?;
119
133
let expr = if p. eat_keyword ( kw:: Underscore ) { None } else { Some ( p. parse_expr ( ) ?) } ;
120
134
ast:: InlineAsmOperand :: Out { reg, expr, late : true }
121
135
} else if !is_global_asm && p. eat_keyword ( sym:: inout) {
122
- let reg = parse_reg ( & mut p, & mut explicit_reg) ?;
136
+ let reg = parse_reg ( p, & mut explicit_reg) ?;
123
137
if p. eat_keyword ( kw:: Underscore ) {
124
- let err = ecx . struct_span_err ( p. token . span , "_ cannot be used for input operands" ) ;
138
+ let err = diag . struct_span_err ( p. token . span , "_ cannot be used for input operands" ) ;
125
139
return Err ( err) ;
126
140
}
127
141
let expr = p. parse_expr ( ) ?;
@@ -133,9 +147,9 @@ fn parse_args<'a>(
133
147
ast:: InlineAsmOperand :: InOut { reg, expr, late : false }
134
148
}
135
149
} else if !is_global_asm && p. eat_keyword ( sym:: inlateout) {
136
- let reg = parse_reg ( & mut p, & mut explicit_reg) ?;
150
+ let reg = parse_reg ( p, & mut explicit_reg) ?;
137
151
if p. eat_keyword ( kw:: Underscore ) {
138
- let err = ecx . struct_span_err ( p. token . span , "_ cannot be used for input operands" ) ;
152
+ let err = diag . struct_span_err ( p. token . span , "_ cannot be used for input operands" ) ;
139
153
return Err ( err) ;
140
154
}
141
155
let expr = p. parse_expr ( ) ?;
@@ -154,7 +168,7 @@ fn parse_args<'a>(
154
168
match expr. kind {
155
169
ast:: ExprKind :: Path ( ..) => { }
156
170
_ => {
157
- let err = ecx
171
+ let err = diag
158
172
. struct_span_err ( expr. span , "argument to `sym` must be a path expression" ) ;
159
173
return Err ( err) ;
160
174
}
@@ -173,7 +187,7 @@ fn parse_args<'a>(
173
187
} else {
174
188
"expected operand, clobber_abi, options, or additional template string"
175
189
} ;
176
- let mut err = ecx . struct_span_err ( template. span , errstr) ;
190
+ let mut err = diag . struct_span_err ( template. span , errstr) ;
177
191
err. span_label ( template. span , errstr) ;
178
192
return Err ( err) ;
179
193
}
@@ -193,31 +207,31 @@ fn parse_args<'a>(
193
207
// clobber_abi/options. We do this at the end once we have the full span
194
208
// of the argument available.
195
209
if !args. options_spans . is_empty ( ) {
196
- ecx . struct_span_err ( span, "arguments are not allowed after options" )
210
+ diag . struct_span_err ( span, "arguments are not allowed after options" )
197
211
. span_labels ( args. options_spans . clone ( ) , "previous options" )
198
212
. span_label ( span, "argument" )
199
213
. emit ( ) ;
200
214
} else if let Some ( ( _, abi_span) ) = args. clobber_abis . last ( ) {
201
- ecx . struct_span_err ( span, "arguments are not allowed after clobber_abi" )
215
+ diag . struct_span_err ( span, "arguments are not allowed after clobber_abi" )
202
216
. span_label ( * abi_span, "clobber_abi" )
203
217
. span_label ( span, "argument" )
204
218
. emit ( ) ;
205
219
}
206
220
if explicit_reg {
207
221
if name. is_some ( ) {
208
- ecx . struct_span_err ( span, "explicit register arguments cannot have names" ) . emit ( ) ;
222
+ diag . struct_span_err ( span, "explicit register arguments cannot have names" ) . emit ( ) ;
209
223
}
210
224
args. reg_args . insert ( slot) ;
211
225
} else if let Some ( name) = name {
212
226
if let Some ( & prev) = args. named_args . get ( & name) {
213
- ecx . struct_span_err ( span, & format ! ( "duplicate argument named `{}`" , name) )
227
+ diag . struct_span_err ( span, & format ! ( "duplicate argument named `{}`" , name) )
214
228
. span_label ( args. operands [ prev] . 1 , "previously here" )
215
229
. span_label ( span, "duplicate argument" )
216
230
. emit ( ) ;
217
231
continue ;
218
232
}
219
233
if !args. reg_args . is_empty ( ) {
220
- let mut err = ecx . struct_span_err (
234
+ let mut err = diag . struct_span_err (
221
235
span,
222
236
"named arguments cannot follow explicit register arguments" ,
223
237
) ;
@@ -230,7 +244,7 @@ fn parse_args<'a>(
230
244
args. named_args . insert ( name, slot) ;
231
245
} else {
232
246
if !args. named_args . is_empty ( ) || !args. reg_args . is_empty ( ) {
233
- let mut err = ecx . struct_span_err (
247
+ let mut err = diag . struct_span_err (
234
248
span,
235
249
"positional arguments cannot follow named arguments \
236
250
or explicit register arguments",
@@ -251,21 +265,21 @@ fn parse_args<'a>(
251
265
&& args. options . contains ( ast:: InlineAsmOptions :: READONLY )
252
266
{
253
267
let spans = args. options_spans . clone ( ) ;
254
- ecx . struct_span_err ( spans, "the `nomem` and `readonly` options are mutually exclusive" )
268
+ diag . struct_span_err ( spans, "the `nomem` and `readonly` options are mutually exclusive" )
255
269
. emit ( ) ;
256
270
}
257
271
if args. options . contains ( ast:: InlineAsmOptions :: PURE )
258
272
&& args. options . contains ( ast:: InlineAsmOptions :: NORETURN )
259
273
{
260
274
let spans = args. options_spans . clone ( ) ;
261
- ecx . struct_span_err ( spans, "the `pure` and `noreturn` options are mutually exclusive" )
275
+ diag . struct_span_err ( spans, "the `pure` and `noreturn` options are mutually exclusive" )
262
276
. emit ( ) ;
263
277
}
264
278
if args. options . contains ( ast:: InlineAsmOptions :: PURE )
265
279
&& !args. options . intersects ( ast:: InlineAsmOptions :: NOMEM | ast:: InlineAsmOptions :: READONLY )
266
280
{
267
281
let spans = args. options_spans . clone ( ) ;
268
- ecx . struct_span_err (
282
+ diag . struct_span_err (
269
283
spans,
270
284
"the `pure` option must be combined with either `nomem` or `readonly`" ,
271
285
)
@@ -296,14 +310,14 @@ fn parse_args<'a>(
296
310
}
297
311
}
298
312
if args. options . contains ( ast:: InlineAsmOptions :: PURE ) && !have_real_output {
299
- ecx . struct_span_err (
313
+ diag . struct_span_err (
300
314
args. options_spans . clone ( ) ,
301
315
"asm with the `pure` option must have at least one output" ,
302
316
)
303
317
. emit ( ) ;
304
318
}
305
319
if args. options . contains ( ast:: InlineAsmOptions :: NORETURN ) && !outputs_sp. is_empty ( ) {
306
- let err = ecx
320
+ let err = diag
307
321
. struct_span_err ( outputs_sp, "asm outputs are not allowed with the `noreturn` option" ) ;
308
322
309
323
// Bail out now since this is likely to confuse MIR
@@ -312,7 +326,7 @@ fn parse_args<'a>(
312
326
313
327
if args. clobber_abis . len ( ) > 0 {
314
328
if is_global_asm {
315
- let err = ecx . struct_span_err (
329
+ let err = diag . struct_span_err (
316
330
args. clobber_abis . iter ( ) . map ( |( _, span) | * span) . collect :: < Vec < Span > > ( ) ,
317
331
"`clobber_abi` cannot be used with `global_asm!`" ,
318
332
) ;
@@ -321,7 +335,7 @@ fn parse_args<'a>(
321
335
return Err ( err) ;
322
336
}
323
337
if !regclass_outputs. is_empty ( ) {
324
- ecx . struct_span_err (
338
+ diag . struct_span_err (
325
339
regclass_outputs. clone ( ) ,
326
340
"asm with `clobber_abi` must specify explicit registers for outputs" ,
327
341
)
0 commit comments