@@ -109,6 +109,8 @@ pub struct Argument<'a> {
109109pub struct FormatSpec < ' a > {
110110 /// Optionally specified character to fill alignment with.
111111 pub fill : Option < char > ,
112+ /// Span of the optionally specified fill character.
113+ pub fill_span : Option < InnerSpan > ,
112114 /// Optionally specified alignment.
113115 pub align : Alignment ,
114116 /// The `+` or `-` flag.
@@ -264,7 +266,7 @@ impl<'a> Iterator for Parser<'a> {
264266 Some ( String ( self . string ( pos + 1 ) ) )
265267 } else {
266268 let arg = self . argument ( lbrace_end) ;
267- if let Some ( rbrace_pos) = self . must_consume ( '}' ) {
269+ if let Some ( rbrace_pos) = self . consume_closing_brace ( & arg ) {
268270 if self . is_source_literal {
269271 let lbrace_byte_pos = self . to_span_index ( pos) ;
270272 let rbrace_byte_pos = self . to_span_index ( rbrace_pos) ;
@@ -450,69 +452,51 @@ impl<'a> Parser<'a> {
450452
451453 /// Forces consumption of the specified character. If the character is not
452454 /// found, an error is emitted.
453- fn must_consume ( & mut self , c : char ) -> Option < usize > {
455+ fn consume_closing_brace ( & mut self , arg : & Argument < ' _ > ) -> Option < usize > {
454456 self . ws ( ) ;
455457
456- if let Some ( & ( pos, maybe) ) = self . cur . peek ( ) {
457- if c == maybe {
458+ let pos;
459+ let description;
460+
461+ if let Some ( & ( peek_pos, maybe) ) = self . cur . peek ( ) {
462+ if maybe == '}' {
458463 self . cur . next ( ) ;
459- Some ( pos)
460- } else {
461- let pos = self . to_span_index ( pos) ;
462- let description = format ! ( "expected `'}}'`, found `{maybe:?}`" ) ;
463- let label = "expected `}`" . to_owned ( ) ;
464- let ( note, secondary_label) = if c == '}' {
465- (
466- Some (
467- "if you intended to print `{`, you can escape it using `{{`" . to_owned ( ) ,
468- ) ,
469- self . last_opening_brace
470- . map ( |sp| ( "because of this opening brace" . to_owned ( ) , sp) ) ,
471- )
472- } else {
473- ( None , None )
474- } ;
475- self . errors . push ( ParseError {
476- description,
477- note,
478- label,
479- span : pos. to ( pos) ,
480- secondary_label,
481- should_be_replaced_with_positional_argument : false ,
482- } ) ;
483- None
464+ return Some ( peek_pos) ;
484465 }
466+
467+ pos = peek_pos;
468+ description = format ! ( "expected `'}}'`, found `{maybe:?}`" ) ;
485469 } else {
486- let description = format ! ( "expected `{c:?} ` but string was terminated" ) ;
470+ description = "expected `'}' ` but string was terminated" . to_owned ( ) ;
487471 // point at closing `"`
488- let pos = self . input . len ( ) - if self . append_newline { 1 } else { 0 } ;
489- let pos = self . to_span_index ( pos) ;
490- if c == '}' {
491- let label = format ! ( "expected `{c:?}`" ) ;
492- let ( note, secondary_label) = if c == '}' {
493- (
494- Some (
495- "if you intended to print `{`, you can escape it using `{{`" . to_owned ( ) ,
496- ) ,
497- self . last_opening_brace
498- . map ( |sp| ( "because of this opening brace" . to_owned ( ) , sp) ) ,
499- )
500- } else {
501- ( None , None )
502- } ;
503- self . errors . push ( ParseError {
504- description,
505- note,
506- label,
507- span : pos. to ( pos) ,
508- secondary_label,
509- should_be_replaced_with_positional_argument : false ,
510- } ) ;
511- } else {
512- self . err ( description, format ! ( "expected `{c:?}`" ) , pos. to ( pos) ) ;
513- }
514- None
472+ pos = self . input . len ( ) - if self . append_newline { 1 } else { 0 } ;
515473 }
474+
475+ let pos = self . to_span_index ( pos) ;
476+
477+ let label = "expected `'}'`" . to_owned ( ) ;
478+ let ( note, secondary_label) = if arg. format . fill == Some ( '}' ) {
479+ (
480+ Some ( "the character `'}'` is interpreted as a fill character because of the `:` that precedes it" . to_owned ( ) ) ,
481+ arg. format . fill_span . map ( |sp| ( "this is not interpreted as a formatting closing brace" . to_owned ( ) , sp) ) ,
482+ )
483+ } else {
484+ (
485+ Some ( "if you intended to print `{`, you can escape it using `{{`" . to_owned ( ) ) ,
486+ self . last_opening_brace . map ( |sp| ( "because of this opening brace" . to_owned ( ) , sp) ) ,
487+ )
488+ } ;
489+
490+ self . errors . push ( ParseError {
491+ description,
492+ note,
493+ label,
494+ span : pos. to ( pos) ,
495+ secondary_label,
496+ should_be_replaced_with_positional_argument : false ,
497+ } ) ;
498+
499+ None
516500 }
517501
518502 /// Consumes all whitespace characters until the first non-whitespace character
@@ -608,6 +592,7 @@ impl<'a> Parser<'a> {
608592 fn format ( & mut self ) -> FormatSpec < ' a > {
609593 let mut spec = FormatSpec {
610594 fill : None ,
595+ fill_span : None ,
611596 align : AlignUnknown ,
612597 sign : None ,
613598 alternate : false ,
@@ -625,9 +610,10 @@ impl<'a> Parser<'a> {
625610 }
626611
627612 // fill character
628- if let Some ( & ( _ , c) ) = self . cur . peek ( ) {
613+ if let Some ( & ( idx , c) ) = self . cur . peek ( ) {
629614 if let Some ( ( _, '>' | '<' | '^' ) ) = self . cur . clone ( ) . nth ( 1 ) {
630615 spec. fill = Some ( c) ;
616+ spec. fill_span = Some ( self . span ( idx, idx + 1 ) ) ;
631617 self . cur . next ( ) ;
632618 }
633619 }
@@ -722,6 +708,7 @@ impl<'a> Parser<'a> {
722708 fn inline_asm ( & mut self ) -> FormatSpec < ' a > {
723709 let mut spec = FormatSpec {
724710 fill : None ,
711+ fill_span : None ,
725712 align : AlignUnknown ,
726713 sign : None ,
727714 alternate : false ,
0 commit comments