Skip to content

Commit a8c7dd4

Browse files
authored
Rollup merge of rust-lang#94030 - ChayimFriedman2:issue-94010, r=petrochenkov
Correctly mark the span of captured arguments in `format_args!()` It should not include the braces, or misspelling suggestions will be wrong. Fixes rust-lang#94010.
2 parents 6156482 + 91adb6c commit a8c7dd4

15 files changed

+105
-74
lines changed

compiler/rustc_builtin_macros/src/asm.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -700,11 +700,11 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
700700
Some(idx)
701701
}
702702
}
703-
parse::ArgumentNamed(name) => match args.named_args.get(&name) {
703+
parse::ArgumentNamed(name, span) => match args.named_args.get(&name) {
704704
Some(&idx) => Some(idx),
705705
None => {
706706
let msg = format!("there is no argument named `{}`", name);
707-
ecx.struct_span_err(span, &msg).emit();
707+
ecx.struct_span_err(template_span.from_inner(span), &msg).emit();
708708
None
709709
}
710710
},

compiler/rustc_builtin_macros/src/format.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_errors::{pluralize, Applicability, DiagnosticBuilder};
1111
use rustc_expand::base::{self, *};
1212
use rustc_parse_format as parse;
1313
use rustc_span::symbol::{sym, Ident, Symbol};
14-
use rustc_span::{MultiSpan, Span};
14+
use rustc_span::{InnerSpan, MultiSpan, Span};
1515
use smallvec::SmallVec;
1616

1717
use std::borrow::Cow;
@@ -26,7 +26,7 @@ enum ArgumentType {
2626
enum Position {
2727
Exact(usize),
2828
Capture(usize),
29-
Named(Symbol),
29+
Named(Symbol, InnerSpan),
3030
}
3131

3232
struct Context<'a, 'b> {
@@ -247,13 +247,13 @@ impl<'a, 'b> Context<'a, 'b> {
247247
match *p {
248248
parse::String(_) => {}
249249
parse::NextArgument(ref mut arg) => {
250-
if let parse::ArgumentNamed(s) = arg.position {
250+
if let parse::ArgumentNamed(s, _) = arg.position {
251251
arg.position = parse::ArgumentIs(lookup(s));
252252
}
253-
if let parse::CountIsName(s) = arg.format.width {
253+
if let parse::CountIsName(s, _) = arg.format.width {
254254
arg.format.width = parse::CountIsParam(lookup(s));
255255
}
256-
if let parse::CountIsName(s) = arg.format.precision {
256+
if let parse::CountIsName(s, _) = arg.format.precision {
257257
arg.format.precision = parse::CountIsParam(lookup(s));
258258
}
259259
}
@@ -276,7 +276,7 @@ impl<'a, 'b> Context<'a, 'b> {
276276
// it's written second, so it should come after width/precision.
277277
let pos = match arg.position {
278278
parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => Exact(i),
279-
parse::ArgumentNamed(s) => Named(s),
279+
parse::ArgumentNamed(s, span) => Named(s, span),
280280
};
281281

282282
let ty = Placeholder(match arg.format.ty {
@@ -346,8 +346,8 @@ impl<'a, 'b> Context<'a, 'b> {
346346
parse::CountIsParam(i) => {
347347
self.verify_arg_type(Exact(i), Count);
348348
}
349-
parse::CountIsName(s) => {
350-
self.verify_arg_type(Named(s), Count);
349+
parse::CountIsName(s, span) => {
350+
self.verify_arg_type(Named(s, span), Count);
351351
}
352352
}
353353
}
@@ -533,7 +533,7 @@ impl<'a, 'b> Context<'a, 'b> {
533533
}
534534
}
535535

536-
Named(name) => {
536+
Named(name, span) => {
537537
match self.names.get(&name) {
538538
Some(&idx) => {
539539
// Treat as positional arg.
@@ -548,7 +548,7 @@ impl<'a, 'b> Context<'a, 'b> {
548548
self.arg_types.push(Vec::new());
549549
self.arg_unique_types.push(Vec::new());
550550
let span = if self.is_literal {
551-
*self.arg_spans.get(self.curpiece).unwrap_or(&self.fmtsp)
551+
self.fmtsp.from_inner(span)
552552
} else {
553553
self.fmtsp
554554
};
@@ -559,7 +559,7 @@ impl<'a, 'b> Context<'a, 'b> {
559559
} else {
560560
let msg = format!("there is no argument named `{}`", name);
561561
let sp = if self.is_literal {
562-
*self.arg_spans.get(self.curpiece).unwrap_or(&self.fmtsp)
562+
self.fmtsp.from_inner(span)
563563
} else {
564564
self.fmtsp
565565
};
@@ -629,7 +629,7 @@ impl<'a, 'b> Context<'a, 'b> {
629629
}
630630
parse::CountImplied => count(sym::Implied, None),
631631
// should never be the case, names are already resolved
632-
parse::CountIsName(_) => panic!("should never happen"),
632+
parse::CountIsName(..) => panic!("should never happen"),
633633
}
634634
}
635635

@@ -676,7 +676,7 @@ impl<'a, 'b> Context<'a, 'b> {
676676

677677
// should never be the case, because names are already
678678
// resolved.
679-
parse::ArgumentNamed(_) => panic!("should never happen"),
679+
parse::ArgumentNamed(..) => panic!("should never happen"),
680680
}
681681
};
682682

compiler/rustc_parse_format/src/lib.rs

+10-6
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ pub enum Position {
9595
/// The argument is located at a specific index given in the format
9696
ArgumentIs(usize),
9797
/// The argument has a name.
98-
ArgumentNamed(Symbol),
98+
ArgumentNamed(Symbol, InnerSpan),
9999
}
100100

101101
impl Position {
@@ -147,7 +147,7 @@ pub enum Count {
147147
/// The count is specified explicitly.
148148
CountIs(usize),
149149
/// The count is specified by the argument with the given name.
150-
CountIsName(Symbol),
150+
CountIsName(Symbol, InnerSpan),
151151
/// The count is specified by the argument at the given index.
152152
CountIsParam(usize),
153153
/// The count is implied and cannot be explicitly specified.
@@ -494,8 +494,11 @@ impl<'a> Parser<'a> {
494494
Some(ArgumentIs(i))
495495
} else {
496496
match self.cur.peek() {
497-
Some(&(_, c)) if rustc_lexer::is_id_start(c) => {
498-
Some(ArgumentNamed(Symbol::intern(self.word())))
497+
Some(&(start, c)) if rustc_lexer::is_id_start(c) => {
498+
let word = self.word();
499+
let end = start + word.len();
500+
let span = self.to_span_index(start).to(self.to_span_index(end));
501+
Some(ArgumentNamed(Symbol::intern(word), span))
499502
}
500503

501504
// This is an `ArgumentNext`.
@@ -662,8 +665,9 @@ impl<'a> Parser<'a> {
662665
if word.is_empty() {
663666
self.cur = tmp;
664667
(CountImplied, None)
665-
} else if self.consume('$') {
666-
(CountIsName(Symbol::intern(word)), None)
668+
} else if let Some(end) = self.consume_pos('$') {
669+
let span = self.to_span_index(start + 1).to(self.to_span_index(end));
670+
(CountIsName(Symbol::intern(word), span), None)
667671
} else {
668672
self.cur = tmp;
669673
(CountImplied, None)

compiler/rustc_parse_format/src/tests.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,8 @@ fn format_counts() {
221221
fill: None,
222222
align: AlignUnknown,
223223
flags: 0,
224-
precision: CountIsName(Symbol::intern("b")),
225-
width: CountIsName(Symbol::intern("a")),
224+
precision: CountIsName(Symbol::intern("b"), InnerSpan::new(6, 7)),
225+
width: CountIsName(Symbol::intern("a"), InnerSpan::new(4, 4)),
226226
precision_span: None,
227227
width_span: None,
228228
ty: "?",

compiler/rustc_trait_selection/src/traits/on_unimplemented.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -309,23 +309,23 @@ impl<'tcx> OnUnimplementedFormatString {
309309
Piece::String(_) => (), // Normal string, no need to check it
310310
Piece::NextArgument(a) => match a.position {
311311
// `{Self}` is allowed
312-
Position::ArgumentNamed(s) if s == kw::SelfUpper => (),
312+
Position::ArgumentNamed(s, _) if s == kw::SelfUpper => (),
313313
// `{ThisTraitsName}` is allowed
314-
Position::ArgumentNamed(s) if s == name => (),
314+
Position::ArgumentNamed(s, _) if s == name => (),
315315
// `{from_method}` is allowed
316-
Position::ArgumentNamed(s) if s == sym::from_method => (),
316+
Position::ArgumentNamed(s, _) if s == sym::from_method => (),
317317
// `{from_desugaring}` is allowed
318-
Position::ArgumentNamed(s) if s == sym::from_desugaring => (),
318+
Position::ArgumentNamed(s, _) if s == sym::from_desugaring => (),
319319
// `{ItemContext}` is allowed
320-
Position::ArgumentNamed(s) if s == sym::ItemContext => (),
320+
Position::ArgumentNamed(s, _) if s == sym::ItemContext => (),
321321
// `{integral}` and `{integer}` and `{float}` are allowed
322-
Position::ArgumentNamed(s)
322+
Position::ArgumentNamed(s, _)
323323
if s == sym::integral || s == sym::integer_ || s == sym::float =>
324324
{
325325
()
326326
}
327327
// So is `{A}` if A is a type parameter
328-
Position::ArgumentNamed(s) => {
328+
Position::ArgumentNamed(s, _) => {
329329
match generics.params.iter().find(|param| param.name == s) {
330330
Some(_) => (),
331331
None => {
@@ -392,7 +392,7 @@ impl<'tcx> OnUnimplementedFormatString {
392392
.map(|p| match p {
393393
Piece::String(s) => s,
394394
Piece::NextArgument(a) => match a.position {
395-
Position::ArgumentNamed(s) => match generic_map.get(&s) {
395+
Position::ArgumentNamed(s, _) => match generic_map.get(&s) {
396396
Some(val) => val,
397397
None if s == name => &trait_str,
398398
None => {

src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ LL | asm!("{1}", in(reg) foo);
2323
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
2424

2525
error: there is no argument named `a`
26-
--> $DIR/bad-template.rs:36:15
26+
--> $DIR/bad-template.rs:36:16
2727
|
2828
LL | asm!("{a}");
29-
| ^^^
29+
| ^
3030

3131
error: invalid reference to argument at index 0
3232
--> $DIR/bad-template.rs:38:15
@@ -123,10 +123,10 @@ LL | global_asm!("{1}", const FOO);
123123
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
124124

125125
error: there is no argument named `a`
126-
--> $DIR/bad-template.rs:63:14
126+
--> $DIR/bad-template.rs:63:15
127127
|
128128
LL | global_asm!("{a}");
129-
| ^^^
129+
| ^
130130

131131
error: invalid reference to argument at index 0
132132
--> $DIR/bad-template.rs:65:14

src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ LL | asm!("{1}", in(reg) foo);
2323
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
2424

2525
error: there is no argument named `a`
26-
--> $DIR/bad-template.rs:36:15
26+
--> $DIR/bad-template.rs:36:16
2727
|
2828
LL | asm!("{a}");
29-
| ^^^
29+
| ^
3030

3131
error: invalid reference to argument at index 0
3232
--> $DIR/bad-template.rs:38:15
@@ -123,10 +123,10 @@ LL | global_asm!("{1}", const FOO);
123123
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
124124

125125
error: there is no argument named `a`
126-
--> $DIR/bad-template.rs:63:14
126+
--> $DIR/bad-template.rs:63:15
127127
|
128128
LL | global_asm!("{a}");
129-
| ^^^
129+
| ^
130130

131131
error: invalid reference to argument at index 0
132132
--> $DIR/bad-template.rs:65:14

src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ LL | asm!("{1}", in(reg) foo);
2323
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
2424

2525
error: there is no argument named `a`
26-
--> $DIR/bad-template.rs:36:15
26+
--> $DIR/bad-template.rs:36:16
2727
|
2828
LL | asm!("{a}");
29-
| ^^^
29+
| ^
3030

3131
error: invalid reference to argument at index 0
3232
--> $DIR/bad-template.rs:38:15
@@ -123,10 +123,10 @@ LL | global_asm!("{1}", const FOO);
123123
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
124124

125125
error: there is no argument named `a`
126-
--> $DIR/bad-template.rs:63:14
126+
--> $DIR/bad-template.rs:63:15
127127
|
128128
LL | global_asm!("{a}");
129-
| ^^^
129+
| ^
130130

131131
error: invalid reference to argument at index 0
132132
--> $DIR/bad-template.rs:65:14

src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ LL | asm!("{1}", in(reg) foo);
2323
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
2424

2525
error: there is no argument named `a`
26-
--> $DIR/bad-template.rs:36:15
26+
--> $DIR/bad-template.rs:36:16
2727
|
2828
LL | asm!("{a}");
29-
| ^^^
29+
| ^
3030

3131
error: invalid reference to argument at index 0
3232
--> $DIR/bad-template.rs:38:15
@@ -123,10 +123,10 @@ LL | global_asm!("{1}", const FOO);
123123
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
124124

125125
error: there is no argument named `a`
126-
--> $DIR/bad-template.rs:63:14
126+
--> $DIR/bad-template.rs:63:15
127127
|
128128
LL | global_asm!("{a}");
129-
| ^^^
129+
| ^
130130

131131
error: invalid reference to argument at index 0
132132
--> $DIR/bad-template.rs:65:14

src/test/ui/fmt/format-args-capture-issue-93378.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ error: invalid reference to positional argument 0 (no arguments were given)
1010
--> $DIR/format-args-capture-issue-93378.rs:9:23
1111
|
1212
LL | println!("{a:.n$} {b:.*}");
13-
| ------- ^^^--^
14-
| | |
15-
| | this precision flag adds an extra required argument at position 0, which is why there are 3 arguments expected
16-
| this parameter corresponds to the precision flag
13+
| - ^^^--^
14+
| | |
15+
| | this precision flag adds an extra required argument at position 0, which is why there are 3 arguments expected
16+
| this parameter corresponds to the precision flag
1717
|
1818
= note: positional arguments are zero-based
1919
= note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fn main() {
2+
const FOO: i32 = 123;
3+
println!("{foo:X}");
4+
//~^ ERROR: cannot find value `foo` in this scope
5+
println!("{:.foo$}", 0);
6+
//~^ ERROR: cannot find value `foo` in this scope
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0425]: cannot find value `foo` in this scope
2+
--> $DIR/format-args-capture-issue-94010.rs:3:16
3+
|
4+
LL | const FOO: i32 = 123;
5+
| --------------------- similarly named constant `FOO` defined here
6+
LL | println!("{foo:X}");
7+
| ^^^ help: a constant with a similar name exists (notice the capitalization): `FOO`
8+
9+
error[E0425]: cannot find value `foo` in this scope
10+
--> $DIR/format-args-capture-issue-94010.rs:5:18
11+
|
12+
LL | const FOO: i32 = 123;
13+
| --------------------- similarly named constant `FOO` defined here
14+
...
15+
LL | println!("{:.foo$}", 0);
16+
| ^^^ help: a constant with a similar name exists (notice the capitalization): `FOO`
17+
18+
error: aborting due to 2 previous errors
19+
20+
For more information about this error, try `rustc --explain E0425`.

0 commit comments

Comments
 (0)