Rollup merge of #73670 - davidhewitt:format-args-capture, r=varkor

Add `format_args_capture` feature

This is the initial implementation PR for [RFC 2795](https://github.com/rust-lang/rfcs/pull/2795).

Note that, as dicussed in the tracking issue (#67984), the feature gate has been called `format_args_capture`.

Next up I guess I need to add documentation for this feature. I've not written any docs before for rustc / std so I would appreciate suggestions on where I should add docs.
This commit is contained in:
Manish Goregaokar 2020-07-03 17:16:52 -07:00 committed by GitHub
commit 4a8d9ea80f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 305 additions and 5 deletions

View file

@ -0,0 +1,6 @@
fn main() {
format!("{foo}"); //~ ERROR: there is no argument named `foo`
// panic! doesn't hit format_args! unless there are two or more arguments.
panic!("{foo} {bar}", bar=1); //~ ERROR: there is no argument named `foo`
}

View file

@ -0,0 +1,18 @@
error: there is no argument named `foo`
--> $DIR/feature-gate-format-args-capture.rs:2:14
|
LL | format!("{foo}");
| ^^^^^
|
= help: if you intended to capture `foo` from the surrounding scope, add `#![feature(format_args_capture)]` to the crate attributes
error: there is no argument named `foo`
--> $DIR/feature-gate-format-args-capture.rs:5:13
|
LL | panic!("{foo} {bar}", bar=1);
| ^^^^^
|
= help: if you intended to capture `foo` from the surrounding scope, add `#![feature(format_args_capture)]` to the crate attributes
error: aborting due to 2 previous errors

View file

@ -0,0 +1,6 @@
#![feature(format_args_capture)]
fn main() {
format!(concat!("{foo}")); //~ ERROR: there is no argument named `foo`
format!(concat!("{ba", "r} {}"), 1); //~ ERROR: there is no argument named `bar`
}

View file

@ -0,0 +1,22 @@
error: there is no argument named `foo`
--> $DIR/format-args-capture-macro-hygiene.rs:4:13
|
LL | format!(concat!("{foo}"));
| ^^^^^^^^^^^^^^^^
|
= note: did you intend to capture a variable `foo` from the surrounding scope?
= note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: there is no argument named `bar`
--> $DIR/format-args-capture-macro-hygiene.rs:5:13
|
LL | format!(concat!("{ba", "r} {}"), 1);
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= note: did you intend to capture a variable `bar` from the surrounding scope?
= note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors

View file

@ -0,0 +1,22 @@
#![feature(format_args_capture)]
fn main() {
format!("{} {foo} {} {bar} {}", 1, 2, 3);
//~^ ERROR: cannot find value `foo` in this scope
//~^^ ERROR: cannot find value `bar` in this scope
format!("{foo}"); //~ ERROR: cannot find value `foo` in this scope
format!("{valuea} {valueb}", valuea=5, valuec=7);
//~^ ERROR cannot find value `valueb` in this scope
//~^^ ERROR named argument never used
format!(r##"
{foo}
"##);
//~^^^^^ ERROR: cannot find value `foo` in this scope
panic!("{foo} {bar}", bar=1); //~ ERROR: cannot find value `foo` in this scope
}

View file

@ -0,0 +1,52 @@
error: named argument never used
--> $DIR/format-args-capture-missing-variables.rs:10:51
|
LL | format!("{valuea} {valueb}", valuea=5, valuec=7);
| ------------------- ^ named argument never used
| |
| formatting specifier missing
error[E0425]: cannot find value `foo` in this scope
--> $DIR/format-args-capture-missing-variables.rs:4:13
|
LL | format!("{} {foo} {} {bar} {}", 1, 2, 3);
| ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
error[E0425]: cannot find value `bar` in this scope
--> $DIR/format-args-capture-missing-variables.rs:4:13
|
LL | format!("{} {foo} {} {bar} {}", 1, 2, 3);
| ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
error[E0425]: cannot find value `foo` in this scope
--> $DIR/format-args-capture-missing-variables.rs:8:13
|
LL | format!("{foo}");
| ^^^^^^^ not found in this scope
error[E0425]: cannot find value `valueb` in this scope
--> $DIR/format-args-capture-missing-variables.rs:10:13
|
LL | format!("{valuea} {valueb}", valuea=5, valuec=7);
| ^^^^^^^^^^^^^^^^^^^ not found in this scope
error[E0425]: cannot find value `foo` in this scope
--> $DIR/format-args-capture-missing-variables.rs:14:13
|
LL | format!(r##"
| _____________^
LL | |
LL | | {foo}
LL | |
LL | | "##);
| |_______^ not found in this scope
error[E0425]: cannot find value `foo` in this scope
--> $DIR/format-args-capture-missing-variables.rs:21:12
|
LL | panic!("{foo} {bar}", bar=1);
| ^^^^^^^^^^^^^ not found in this scope
error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0425`.

View file

@ -0,0 +1,64 @@
// run-pass
// ignore-wasm32
// ignore-wasm64
#![feature(format_args_capture)]
fn main() {
named_argument_takes_precedence_to_captured();
panic_with_single_argument_does_not_get_formatted();
panic_with_multiple_arguments_is_formatted();
formatting_parameters_can_be_captured();
}
fn named_argument_takes_precedence_to_captured() {
let foo = "captured";
let s = format!("{foo}", foo="named");
assert_eq!(&s, "named");
let s = format!("{foo}-{foo}-{foo}", foo="named");
assert_eq!(&s, "named-named-named");
let s = format!("{}-{bar}-{foo}", "positional", bar="named");
assert_eq!(&s, "positional-named-captured");
}
fn panic_with_single_argument_does_not_get_formatted() {
// panic! with a single argument does not perform string formatting.
// RFC #2795 suggests that this may need to change so that captured arguments are formatted.
// For stability reasons this will need to part of an edition change.
let msg = std::panic::catch_unwind(|| {
panic!("{foo}");
}).unwrap_err();
assert_eq!(msg.downcast_ref::<&str>(), Some(&"{foo}"))
}
fn panic_with_multiple_arguments_is_formatted() {
let foo = "captured";
let msg = std::panic::catch_unwind(|| {
panic!("{}-{bar}-{foo}", "positional", bar="named");
}).unwrap_err();
assert_eq!(msg.downcast_ref::<String>(), Some(&"positional-named-captured".to_string()))
}
fn formatting_parameters_can_be_captured() {
let width = 9;
let precision = 3;
let x = 7.0;
let s = format!("{x:width$}");
assert_eq!(&s, " 7");
let s = format!("{x:<width$}");
assert_eq!(&s, "7 ");
let s = format!("{x:-^width$}");
assert_eq!(&s, "----7----");
let s = format!("{x:-^width$.precision$}");
assert_eq!(&s, "--7.000--");
}

View file

@ -63,18 +63,24 @@ error: there is no argument named `foo`
|
LL | format!("{} {foo} {} {bar} {}", 1, 2, 3);
| ^^^^^
|
= help: if you intended to capture `foo` from the surrounding scope, add `#![feature(format_args_capture)]` to the crate attributes
error: there is no argument named `bar`
--> $DIR/ifmt-bad-arg.rs:27:26
|
LL | format!("{} {foo} {} {bar} {}", 1, 2, 3);
| ^^^^^
|
= help: if you intended to capture `bar` from the surrounding scope, add `#![feature(format_args_capture)]` to the crate attributes
error: there is no argument named `foo`
--> $DIR/ifmt-bad-arg.rs:31:14
|
LL | format!("{foo}");
| ^^^^^
|
= help: if you intended to capture `foo` from the surrounding scope, add `#![feature(format_args_capture)]` to the crate attributes
error: multiple unused formatting arguments
--> $DIR/ifmt-bad-arg.rs:32:17
@ -155,6 +161,8 @@ error: there is no argument named `valueb`
|
LL | format!("{valuea} {valueb}", valuea=5, valuec=7);
| ^^^^^^^^
|
= help: if you intended to capture `valueb` from the surrounding scope, add `#![feature(format_args_capture)]` to the crate attributes
error: named argument never used
--> $DIR/ifmt-bad-arg.rs:45:51
@ -205,6 +213,8 @@ error: there is no argument named `foo`
|
LL | {foo}
| ^^^^^
|
= help: if you intended to capture `foo` from the surrounding scope, add `#![feature(format_args_capture)]` to the crate attributes
error: invalid format string: expected `'}'`, found `'t'`
--> $DIR/ifmt-bad-arg.rs:75:1