about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>2022-08-29 16:49:45 +0530
committerGitHub <noreply@github.com>2022-08-29 16:49:45 +0530
commit0b6faca67057ceb99ee3af342d4ba6f1ac407fde (patch)
tree2ca8afd1a123f358dc5938f8305289ec24add362
parent141728fc61254fafe14dbe8387ec08c5ecc046a9 (diff)
parentaebad394142aba6f5dc11a1fad5731e12c351c00 (diff)
downloadrust-0b6faca67057ceb99ee3af342d4ba6f1ac407fde.tar.gz
rust-0b6faca67057ceb99ee3af342d4ba6f1ac407fde.zip
Rollup merge of #101000 - m-ou-se:count-is-star, r=nagisa
Separate CountIsStar from CountIsParam in rustc_parse_format.

`rustc_parse_format`'s parser would result in the exact same output for `{:.*}` and `{:.0$}`, making it hard for diagnostics to handle these cases properly.

This splits those cases by adding a new `CountIsStar` enum variant.

This fixes #100995

Prerequisite for https://github.com/rust-lang/rust/pull/100996
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs12
-rw-r--r--compiler/rustc_parse_format/src/lib.rs4
-rw-r--r--compiler/rustc_parse_format/src/tests.rs2
-rw-r--r--src/test/ui/fmt/ifmt-bad-arg.rs2
-rw-r--r--src/test/ui/fmt/ifmt-bad-arg.stderr13
5 files changed, 24 insertions, 9 deletions
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 2816f81fef1..21004871075 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -541,7 +541,7 @@ impl<'a, 'b> Context<'a, 'b> {
     ) {
         match c {
             parse::CountImplied | parse::CountIs(..) => {}
-            parse::CountIsParam(i) => {
+            parse::CountIsParam(i) | parse::CountIsStar(i) => {
                 self.unused_names_lint.maybe_add_positional_named_arg(
                     self.args.get(i),
                     named_arg_type,
@@ -589,7 +589,7 @@ impl<'a, 'b> Context<'a, 'b> {
             + self
                 .arg_with_formatting
                 .iter()
-                .filter(|fmt| matches!(fmt.precision, parse::CountIsParam(_)))
+                .filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_)))
                 .count();
         if self.names.is_empty() && !numbered_position_args && count != self.num_args() {
             e = self.ecx.struct_span_err(
@@ -639,7 +639,7 @@ impl<'a, 'b> Context<'a, 'b> {
             if let Some(span) = fmt.precision_span {
                 let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end));
                 match fmt.precision {
-                    parse::CountIsParam(pos) if pos > self.num_args() => {
+                    parse::CountIsParam(pos) if pos >= self.num_args() => {
                         e.span_label(
                             span,
                             &format!(
@@ -651,12 +651,12 @@ impl<'a, 'b> Context<'a, 'b> {
                         );
                         zero_based_note = true;
                     }
-                    parse::CountIsParam(pos) => {
+                    parse::CountIsStar(pos) => {
                         let count = self.pieces.len()
                             + self
                                 .arg_with_formatting
                                 .iter()
-                                .filter(|fmt| matches!(fmt.precision, parse::CountIsParam(_)))
+                                .filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_)))
                                 .count();
                         e.span_label(
                             span,
@@ -837,7 +837,7 @@ impl<'a, 'b> Context<'a, 'b> {
         };
         match c {
             parse::CountIs(i) => count(sym::Is, Some(self.ecx.expr_usize(sp, i))),
-            parse::CountIsParam(i) => {
+            parse::CountIsParam(i) | parse::CountIsStar(i) => {
                 // This needs mapping too, as `i` is referring to a macro
                 // argument. If `i` is not found in `count_positions` then
                 // the error had already been emitted elsewhere.
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index b63a173cc29..a9e502016aa 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -167,6 +167,8 @@ pub enum Count<'a> {
     CountIsName(&'a str, InnerSpan),
     /// The count is specified by the argument at the given index.
     CountIsParam(usize),
+    /// The count is specified by a star (like in `{:.*}`) that refers to the argument at the given index.
+    CountIsStar(usize),
     /// The count is implied and cannot be explicitly specified.
     CountImplied,
 }
@@ -618,7 +620,7 @@ impl<'a> Parser<'a> {
                 // We can do this immediately as `position` is resolved later.
                 let i = self.curarg;
                 self.curarg += 1;
-                spec.precision = CountIsParam(i);
+                spec.precision = CountIsStar(i);
             } else {
                 spec.precision = self.count(start + 1);
             }
diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs
index 44ef0cd0eb5..2f8c229c68f 100644
--- a/compiler/rustc_parse_format/src/tests.rs
+++ b/compiler/rustc_parse_format/src/tests.rs
@@ -244,7 +244,7 @@ fn format_counts() {
                 fill: None,
                 align: AlignUnknown,
                 flags: 0,
-                precision: CountIsParam(0),
+                precision: CountIsStar(0),
                 precision_span: Some(InnerSpan { start: 3, end: 5 }),
                 width: CountImplied,
                 width_span: None,
diff --git a/src/test/ui/fmt/ifmt-bad-arg.rs b/src/test/ui/fmt/ifmt-bad-arg.rs
index 84f4cc7f4cc..f00cb05c9eb 100644
--- a/src/test/ui/fmt/ifmt-bad-arg.rs
+++ b/src/test/ui/fmt/ifmt-bad-arg.rs
@@ -94,4 +94,6 @@ tenth number: {}",
     // doesn't exist.
     println!("{:.*}");
     //~^ ERROR 2 positional arguments in format string, but no arguments were given
+    println!("{:.0$}");
+    //~^ ERROR 1 positional argument in format string, but no arguments were given
 }
diff --git a/src/test/ui/fmt/ifmt-bad-arg.stderr b/src/test/ui/fmt/ifmt-bad-arg.stderr
index 5439ee17398..dbb4bc6d937 100644
--- a/src/test/ui/fmt/ifmt-bad-arg.stderr
+++ b/src/test/ui/fmt/ifmt-bad-arg.stderr
@@ -273,6 +273,17 @@ LL |     println!("{:.*}");
    = note: positional arguments are zero-based
    = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
 
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/ifmt-bad-arg.rs:97:15
+   |
+LL |     println!("{:.0$}");
+   |               ^^---^
+   |                 |
+   |                 this precision flag expects an `usize` argument at position 0, but no arguments were given
+   |
+   = note: positional arguments are zero-based
+   = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
+
 error[E0425]: cannot find value `foo` in this scope
   --> $DIR/ifmt-bad-arg.rs:27:18
    |
@@ -339,7 +350,7 @@ LL |     pub fn from_usize(x: &usize) -> ArgumentV1<'_> {
    |            ^^^^^^^^^^
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 37 previous errors
+error: aborting due to 38 previous errors
 
 Some errors have detailed explanations: E0308, E0425.
 For more information about an error, try `rustc --explain E0308`.