Skip to content

Commit 110d8d9

Browse files
authored
Rollup merge of #100851 - Alexendoo:rpf-width-prec-spans, r=fee1-dead
Fix rustc_parse_format precision & width spans When a `precision`/`width` was `CountIsName - {:name$}` or `CountIs - {:10}` the `precision_span`/`width_span` was set to `None` For `width` the name span in `CountIsName(_, name_span)` had its `.start` off by one r? ``@fee1-dead`` / cc ``@PrestonFrom`` since this is similar to #99987
2 parents a163659 + 586c84a commit 110d8d9

File tree

3 files changed

+84
-65
lines changed

3 files changed

+84
-65
lines changed

compiler/rustc_builtin_macros/src/format.rs

+16-11
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ impl<'a, 'b> Context<'a, 'b> {
413413
/// Verifies one piece of a parse string, and remembers it if valid.
414414
/// All errors are not emitted as fatal so we can continue giving errors
415415
/// about this and possibly other format strings.
416-
fn verify_piece(&mut self, p: &parse::Piece<'_>) {
416+
fn verify_piece(&mut self, p: &parse::Piece<'a>) {
417417
match *p {
418418
parse::String(..) => {}
419419
parse::NextArgument(ref arg) => {
@@ -433,6 +433,11 @@ impl<'a, 'b> Context<'a, 'b> {
433433
let has_precision = arg.format.precision != Count::CountImplied;
434434
let has_width = arg.format.width != Count::CountImplied;
435435

436+
if has_precision || has_width {
437+
// push before named params are resolved to aid diagnostics
438+
self.arg_with_formatting.push(arg.format);
439+
}
440+
436441
// argument second, if it's an implicit positional parameter
437442
// it's written second, so it should come after width/precision.
438443
let pos = match arg.position {
@@ -581,7 +586,11 @@ impl<'a, 'b> Context<'a, 'b> {
581586
let mut zero_based_note = false;
582587

583588
let count = self.pieces.len()
584-
+ self.arg_with_formatting.iter().filter(|fmt| fmt.precision_span.is_some()).count();
589+
+ self
590+
.arg_with_formatting
591+
.iter()
592+
.filter(|fmt| matches!(fmt.precision, parse::CountIsParam(_)))
593+
.count();
585594
if self.names.is_empty() && !numbered_position_args && count != self.num_args() {
586595
e = self.ecx.struct_span_err(
587596
sp,
@@ -647,7 +656,7 @@ impl<'a, 'b> Context<'a, 'b> {
647656
+ self
648657
.arg_with_formatting
649658
.iter()
650-
.filter(|fmt| fmt.precision_span.is_some())
659+
.filter(|fmt| matches!(fmt.precision, parse::CountIsParam(_)))
651660
.count();
652661
e.span_label(
653662
span,
@@ -899,26 +908,22 @@ impl<'a, 'b> Context<'a, 'b> {
899908
},
900909
position_span: arg.position_span,
901910
format: parse::FormatSpec {
902-
fill: arg.format.fill,
911+
fill: None,
903912
align: parse::AlignUnknown,
904913
flags: 0,
905914
precision: parse::CountImplied,
906-
precision_span: None,
915+
precision_span: arg.format.precision_span,
907916
width: parse::CountImplied,
908-
width_span: None,
917+
width_span: arg.format.width_span,
909918
ty: arg.format.ty,
910919
ty_span: arg.format.ty_span,
911920
},
912921
};
913922

914923
let fill = arg.format.fill.unwrap_or(' ');
915-
916924
let pos_simple = arg.position.index() == simple_arg.position.index();
917925

918-
if arg.format.precision_span.is_some() || arg.format.width_span.is_some() {
919-
self.arg_with_formatting.push(arg.format);
920-
}
921-
if !pos_simple || arg.format != simple_arg.format || fill != ' ' {
926+
if !pos_simple || arg.format != simple_arg.format {
922927
self.all_pieces_simple = false;
923928
}
924929

compiler/rustc_parse_format/src/lib.rs

+38-43
Original file line numberDiff line numberDiff line change
@@ -264,9 +264,7 @@ impl<'a> Iterator for Parser<'a> {
264264
}
265265
} else {
266266
if self.is_literal {
267-
let start = self.to_span_index(self.cur_line_start);
268-
let end = self.to_span_index(self.input.len());
269-
let span = start.to(end);
267+
let span = self.span(self.cur_line_start, self.input.len());
270268
if self.line_spans.last() != Some(&span) {
271269
self.line_spans.push(span);
272270
}
@@ -384,6 +382,12 @@ impl<'a> Parser<'a> {
384382
InnerOffset(raw + pos + 1)
385383
}
386384

385+
fn span(&self, start_pos: usize, end_pos: usize) -> InnerSpan {
386+
let start = self.to_span_index(start_pos);
387+
let end = self.to_span_index(end_pos);
388+
start.to(end)
389+
}
390+
387391
/// Forces consumption of the specified character. If the character is not
388392
/// found, an error is emitted.
389393
fn must_consume(&mut self, c: char) -> Option<usize> {
@@ -472,9 +476,7 @@ impl<'a> Parser<'a> {
472476
return &self.input[start..pos];
473477
}
474478
'\n' if self.is_literal => {
475-
let start = self.to_span_index(self.cur_line_start);
476-
let end = self.to_span_index(pos);
477-
self.line_spans.push(start.to(end));
479+
self.line_spans.push(self.span(self.cur_line_start, pos));
478480
self.cur_line_start = pos + 1;
479481
self.cur.next();
480482
}
@@ -537,6 +539,10 @@ impl<'a> Parser<'a> {
537539
}
538540
}
539541

542+
fn current_pos(&mut self) -> usize {
543+
if let Some(&(pos, _)) = self.cur.peek() { pos } else { self.input.len() }
544+
}
545+
540546
/// Parses a format specifier at the current position, returning all of the
541547
/// relevant information in the `FormatSpec` struct.
542548
fn format(&mut self) -> FormatSpec<'a> {
@@ -590,39 +596,37 @@ impl<'a> Parser<'a> {
590596
// no '0' flag and '0$' as the width instead.
591597
if let Some(end) = self.consume_pos('$') {
592598
spec.width = CountIsParam(0);
593-
594-
if let Some((pos, _)) = self.cur.peek().cloned() {
595-
spec.width_span = Some(self.to_span_index(pos - 2).to(self.to_span_index(pos)));
596-
}
599+
spec.width_span = Some(self.span(end - 1, end + 1));
597600
havewidth = true;
598-
spec.width_span = Some(self.to_span_index(end - 1).to(self.to_span_index(end + 1)));
599601
} else {
600602
spec.flags |= 1 << (FlagSignAwareZeroPad as u32);
601603
}
602604
}
605+
603606
if !havewidth {
604-
let width_span_start = if let Some((pos, _)) = self.cur.peek() { *pos } else { 0 };
605-
let (w, sp) = self.count(width_span_start);
606-
spec.width = w;
607-
spec.width_span = sp;
607+
let start = self.current_pos();
608+
spec.width = self.count(start);
609+
if spec.width != CountImplied {
610+
let end = self.current_pos();
611+
spec.width_span = Some(self.span(start, end));
612+
}
608613
}
609614

610615
if let Some(start) = self.consume_pos('.') {
611-
if let Some(end) = self.consume_pos('*') {
616+
if self.consume('*') {
612617
// Resolve `CountIsNextParam`.
613618
// We can do this immediately as `position` is resolved later.
614619
let i = self.curarg;
615620
self.curarg += 1;
616621
spec.precision = CountIsParam(i);
617-
spec.precision_span =
618-
Some(self.to_span_index(start).to(self.to_span_index(end + 1)));
619622
} else {
620-
let (p, sp) = self.count(start);
621-
spec.precision = p;
622-
spec.precision_span = sp;
623+
spec.precision = self.count(start + 1);
623624
}
625+
let end = self.current_pos();
626+
spec.precision_span = Some(self.span(start, end));
624627
}
625-
let ty_span_start = self.cur.peek().map(|(pos, _)| *pos);
628+
629+
let ty_span_start = self.current_pos();
626630
// Optional radix followed by the actual format specifier
627631
if self.consume('x') {
628632
if self.consume('?') {
@@ -642,11 +646,9 @@ impl<'a> Parser<'a> {
642646
spec.ty = "?";
643647
} else {
644648
spec.ty = self.word();
645-
let ty_span_end = self.cur.peek().map(|(pos, _)| *pos);
646649
if !spec.ty.is_empty() {
647-
spec.ty_span = ty_span_start
648-
.and_then(|s| ty_span_end.map(|e| (s, e)))
649-
.map(|(start, end)| self.to_span_index(start).to(self.to_span_index(end)));
650+
let ty_span_end = self.current_pos();
651+
spec.ty_span = Some(self.span(ty_span_start, ty_span_end));
650652
}
651653
}
652654
spec
@@ -670,13 +672,11 @@ impl<'a> Parser<'a> {
670672
return spec;
671673
}
672674

673-
let ty_span_start = self.cur.peek().map(|(pos, _)| *pos);
675+
let ty_span_start = self.current_pos();
674676
spec.ty = self.word();
675-
let ty_span_end = self.cur.peek().map(|(pos, _)| *pos);
676677
if !spec.ty.is_empty() {
677-
spec.ty_span = ty_span_start
678-
.and_then(|s| ty_span_end.map(|e| (s, e)))
679-
.map(|(start, end)| self.to_span_index(start).to(self.to_span_index(end)));
678+
let ty_span_end = self.current_pos();
679+
spec.ty_span = Some(self.span(ty_span_start, ty_span_end));
680680
}
681681

682682
spec
@@ -685,26 +685,21 @@ impl<'a> Parser<'a> {
685685
/// Parses a `Count` parameter at the current position. This does not check
686686
/// for 'CountIsNextParam' because that is only used in precision, not
687687
/// width.
688-
fn count(&mut self, start: usize) -> (Count<'a>, Option<InnerSpan>) {
688+
fn count(&mut self, start: usize) -> Count<'a> {
689689
if let Some(i) = self.integer() {
690-
if let Some(end) = self.consume_pos('$') {
691-
let span = self.to_span_index(start).to(self.to_span_index(end + 1));
692-
(CountIsParam(i), Some(span))
693-
} else {
694-
(CountIs(i), None)
695-
}
690+
if self.consume('$') { CountIsParam(i) } else { CountIs(i) }
696691
} else {
697692
let tmp = self.cur.clone();
698693
let word = self.word();
699694
if word.is_empty() {
700695
self.cur = tmp;
701-
(CountImplied, None)
696+
CountImplied
702697
} else if let Some(end) = self.consume_pos('$') {
703-
let span = self.to_span_index(start + 1).to(self.to_span_index(end));
704-
(CountIsName(word, span), None)
698+
let name_span = self.span(start, end);
699+
CountIsName(word, name_span)
705700
} else {
706701
self.cur = tmp;
707-
(CountImplied, None)
702+
CountImplied
708703
}
709704
}
710705
}
@@ -737,7 +732,7 @@ impl<'a> Parser<'a> {
737732
"invalid argument name `_`",
738733
"invalid argument name",
739734
"argument name cannot be a single underscore",
740-
self.to_span_index(start).to(self.to_span_index(end)),
735+
self.span(start, end),
741736
);
742737
}
743738
word

compiler/rustc_parse_format/src/tests.rs

+30-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::*;
22

3+
#[track_caller]
34
fn same(fmt: &'static str, p: &[Piece<'static>]) {
45
let parser = Parser::new(fmt, None, None, false, ParseMode::Format);
56
assert_eq!(parser.collect::<Vec<Piece<'static>>>(), p);
@@ -190,9 +191,9 @@ fn format_counts() {
190191
align: AlignUnknown,
191192
flags: 0,
192193
precision: CountImplied,
193-
width: CountIs(10),
194194
precision_span: None,
195-
width_span: None,
195+
width: CountIs(10),
196+
width_span: Some(InnerSpan { start: 3, end: 5 }),
196197
ty: "x",
197198
ty_span: None,
198199
},
@@ -208,9 +209,9 @@ fn format_counts() {
208209
align: AlignUnknown,
209210
flags: 0,
210211
precision: CountIs(10),
212+
precision_span: Some(InnerSpan { start: 6, end: 9 }),
211213
width: CountIsParam(10),
212-
precision_span: None,
213-
width_span: Some(InnerSpan::new(3, 6)),
214+
width_span: Some(InnerSpan { start: 3, end: 6 }),
214215
ty: "x",
215216
ty_span: None,
216217
},
@@ -226,9 +227,9 @@ fn format_counts() {
226227
align: AlignUnknown,
227228
flags: 0,
228229
precision: CountIs(10),
230+
precision_span: Some(InnerSpan { start: 6, end: 9 }),
229231
width: CountIsParam(0),
230-
precision_span: None,
231-
width_span: Some(InnerSpan::new(4, 6)),
232+
width_span: Some(InnerSpan { start: 4, end: 6 }),
232233
ty: "x",
233234
ty_span: None,
234235
},
@@ -244,8 +245,8 @@ fn format_counts() {
244245
align: AlignUnknown,
245246
flags: 0,
246247
precision: CountIsParam(0),
248+
precision_span: Some(InnerSpan { start: 3, end: 5 }),
247249
width: CountImplied,
248-
precision_span: Some(InnerSpan::new(3, 5)),
249250
width_span: None,
250251
ty: "x",
251252
ty_span: None,
@@ -279,15 +280,33 @@ fn format_counts() {
279280
fill: None,
280281
align: AlignUnknown,
281282
flags: 0,
282-
precision: CountIsName("b", InnerSpan::new(6, 7)),
283-
width: CountIsName("a", InnerSpan::new(4, 4)),
284-
precision_span: None,
285-
width_span: None,
283+
precision: CountIsName("b", InnerSpan { start: 6, end: 7 }),
284+
precision_span: Some(InnerSpan { start: 5, end: 8 }),
285+
width: CountIsName("a", InnerSpan { start: 3, end: 4 }),
286+
width_span: Some(InnerSpan { start: 3, end: 5 }),
286287
ty: "?",
287288
ty_span: None,
288289
},
289290
})],
290291
);
292+
same(
293+
"{:.4}",
294+
&[NextArgument(Argument {
295+
position: ArgumentImplicitlyIs(0),
296+
position_span: InnerSpan { start: 2, end: 2 },
297+
format: FormatSpec {
298+
fill: None,
299+
align: AlignUnknown,
300+
flags: 0,
301+
precision: CountIs(4),
302+
precision_span: Some(InnerSpan { start: 3, end: 5 }),
303+
width: CountImplied,
304+
width_span: None,
305+
ty: "",
306+
ty_span: None,
307+
},
308+
})],
309+
)
291310
}
292311
#[test]
293312
fn format_flags() {

0 commit comments

Comments
 (0)