@@ -19,6 +19,12 @@ struct AsmArgs {
19
19
options_spans : Vec < Span > ,
20
20
}
21
21
22
+ impl AsmArgs {
23
+ fn option_is_set ( & self , option : ast:: InlineAsmOptions ) -> bool {
24
+ ( self . options & option) == option
25
+ }
26
+ }
27
+
22
28
fn parse_args < ' a > (
23
29
ecx : & mut ExtCtxt < ' a > ,
24
30
sp : Span ,
@@ -283,27 +289,72 @@ fn parse_args<'a>(
283
289
Ok ( args)
284
290
}
285
291
292
+ fn warn_duplicate_option < ' a > ( p : & mut Parser < ' a > , span : Span ) {
293
+ let mut warn = if let Ok ( snippet) = p. sess . source_map ( ) . span_to_snippet ( span) {
294
+ p. sess
295
+ . span_diagnostic
296
+ . struct_span_warn ( span, & format ! ( "the `{}` option was already provided" , snippet) )
297
+ } else {
298
+ p. sess . span_diagnostic . struct_span_warn ( span, "this option was already provided" )
299
+ } ;
300
+ warn. span_suggestion (
301
+ span,
302
+ "remove this option" ,
303
+ String :: new ( ) ,
304
+ Applicability :: MachineApplicable ,
305
+ ) ;
306
+ warn. emit ( ) ;
307
+ }
308
+
286
309
fn parse_options < ' a > ( p : & mut Parser < ' a > , args : & mut AsmArgs ) -> Result < ( ) , DiagnosticBuilder < ' a > > {
287
310
let span_start = p. prev_token . span ;
288
311
289
312
p. expect ( & token:: OpenDelim ( token:: DelimToken :: Paren ) ) ?;
290
313
291
314
while !p. eat ( & token:: CloseDelim ( token:: DelimToken :: Paren ) ) {
292
315
if p. eat ( & token:: Ident ( sym:: pure, false ) ) {
293
- args. options |= ast:: InlineAsmOptions :: PURE ;
316
+ if !args. option_is_set ( ast:: InlineAsmOptions :: PURE ) {
317
+ args. options |= ast:: InlineAsmOptions :: PURE ;
318
+ } else {
319
+ warn_duplicate_option ( p, p. prev_token . span ) ;
320
+ }
294
321
} else if p. eat ( & token:: Ident ( sym:: nomem, false ) ) {
295
- args. options |= ast:: InlineAsmOptions :: NOMEM ;
322
+ if !args. option_is_set ( ast:: InlineAsmOptions :: NOMEM ) {
323
+ args. options |= ast:: InlineAsmOptions :: NOMEM ;
324
+ } else {
325
+ warn_duplicate_option ( p, p. prev_token . span ) ;
326
+ }
296
327
} else if p. eat ( & token:: Ident ( sym:: readonly, false ) ) {
297
- args. options |= ast:: InlineAsmOptions :: READONLY ;
328
+ if !args. option_is_set ( ast:: InlineAsmOptions :: READONLY ) {
329
+ args. options |= ast:: InlineAsmOptions :: READONLY ;
330
+ } else {
331
+ warn_duplicate_option ( p, p. prev_token . span ) ;
332
+ }
298
333
} else if p. eat ( & token:: Ident ( sym:: preserves_flags, false ) ) {
299
- args. options |= ast:: InlineAsmOptions :: PRESERVES_FLAGS ;
334
+ if !args. option_is_set ( ast:: InlineAsmOptions :: PRESERVES_FLAGS ) {
335
+ args. options |= ast:: InlineAsmOptions :: PRESERVES_FLAGS ;
336
+ } else {
337
+ warn_duplicate_option ( p, p. prev_token . span ) ;
338
+ }
300
339
} else if p. eat ( & token:: Ident ( sym:: noreturn, false ) ) {
301
- args. options |= ast:: InlineAsmOptions :: NORETURN ;
340
+ if !args. option_is_set ( ast:: InlineAsmOptions :: NORETURN ) {
341
+ args. options |= ast:: InlineAsmOptions :: NORETURN ;
342
+ } else {
343
+ warn_duplicate_option ( p, p. prev_token . span ) ;
344
+ }
302
345
} else if p. eat ( & token:: Ident ( sym:: nostack, false ) ) {
303
- args. options |= ast:: InlineAsmOptions :: NOSTACK ;
346
+ if !args. option_is_set ( ast:: InlineAsmOptions :: NOSTACK ) {
347
+ args. options |= ast:: InlineAsmOptions :: NOSTACK ;
348
+ } else {
349
+ warn_duplicate_option ( p, p. prev_token . span ) ;
350
+ }
304
351
} else {
305
352
p. expect ( & token:: Ident ( sym:: att_syntax, false ) ) ?;
306
- args. options |= ast:: InlineAsmOptions :: ATT_SYNTAX ;
353
+ if !args. option_is_set ( ast:: InlineAsmOptions :: ATT_SYNTAX ) {
354
+ args. options |= ast:: InlineAsmOptions :: ATT_SYNTAX ;
355
+ } else {
356
+ warn_duplicate_option ( p, p. prev_token . span ) ;
357
+ }
307
358
}
308
359
309
360
// Allow trailing commas
0 commit comments