@@ -19,6 +19,12 @@ struct AsmArgs {
1919 options_spans : Vec < Span > ,
2020}
2121
22+ impl AsmArgs {
23+ fn option_is_set ( & self , option : ast:: InlineAsmOptions ) -> bool {
24+ ( self . options & option) == option
25+ }
26+ }
27+
2228fn parse_args < ' a > (
2329 ecx : & mut ExtCtxt < ' a > ,
2430 sp : Span ,
@@ -283,27 +289,72 @@ fn parse_args<'a>(
283289 Ok ( args)
284290}
285291
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+
286309fn parse_options < ' a > ( p : & mut Parser < ' a > , args : & mut AsmArgs ) -> Result < ( ) , DiagnosticBuilder < ' a > > {
287310 let span_start = p. prev_token . span ;
288311
289312 p. expect ( & token:: OpenDelim ( token:: DelimToken :: Paren ) ) ?;
290313
291314 while !p. eat ( & token:: CloseDelim ( token:: DelimToken :: Paren ) ) {
292315 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+ }
294321 } 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+ }
296327 } 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+ }
298333 } 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+ }
300339 } 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+ }
302345 } 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+ }
304351 } else {
305352 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+ }
307358 }
308359
309360 // Allow trailing commas
0 commit comments