mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-13 12:36:47 +00:00
Stabilize format_args_capture
Works as expected, and there are widespread reports of success with it, as well as interest in it.
This commit is contained in:
parent
89c3d84b75
commit
8c9bfaa5f3
@ -3,7 +3,7 @@
|
||||
#![feature(bool_to_option)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(format_args_capture)]
|
||||
#![cfg_attr(bootstrap, feature(format_args_capture))]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(iter_zip)]
|
||||
#![feature(let_else)]
|
||||
|
@ -527,17 +527,9 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
self.verify_arg_type(Exact(idx), ty)
|
||||
}
|
||||
None => {
|
||||
let capture_feature_enabled = self
|
||||
.ecx
|
||||
.ecfg
|
||||
.features
|
||||
.map_or(false, |features| features.format_args_capture);
|
||||
|
||||
// For the moment capturing variables from format strings expanded from macros is
|
||||
// disabled (see RFC #2795)
|
||||
let can_capture = capture_feature_enabled && self.is_literal;
|
||||
|
||||
if can_capture {
|
||||
if self.is_literal {
|
||||
// Treat this name as a variable to capture from the surrounding scope
|
||||
let idx = self.args.len();
|
||||
self.arg_types.push(Vec::new());
|
||||
@ -559,23 +551,15 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||
};
|
||||
let mut err = self.ecx.struct_span_err(sp, &msg[..]);
|
||||
|
||||
if capture_feature_enabled && !self.is_literal {
|
||||
err.note(&format!(
|
||||
"did you intend to capture a variable `{}` from \
|
||||
the surrounding scope?",
|
||||
name
|
||||
));
|
||||
err.note(
|
||||
"to avoid ambiguity, `format_args!` cannot capture variables \
|
||||
when the format string is expanded from a macro",
|
||||
);
|
||||
} else if self.ecx.parse_sess().unstable_features.is_nightly_build() {
|
||||
err.help(&format!(
|
||||
"if you intended to capture `{}` from the surrounding scope, add \
|
||||
`#![feature(format_args_capture)]` to the crate attributes",
|
||||
name
|
||||
));
|
||||
}
|
||||
err.note(&format!(
|
||||
"did you intend to capture a variable `{}` from \
|
||||
the surrounding scope?",
|
||||
name
|
||||
));
|
||||
err.note(
|
||||
"to avoid ambiguity, `format_args!` cannot capture variables \
|
||||
when the format string is expanded from a macro",
|
||||
);
|
||||
|
||||
err.emit();
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(backtrace)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(format_args_capture)]
|
||||
#![cfg_attr(bootstrap, feature(format_args_capture))]
|
||||
#![feature(iter_zip)]
|
||||
#![feature(let_else)]
|
||||
#![feature(nll)]
|
||||
|
@ -1,7 +1,7 @@
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(destructuring_assignment)]
|
||||
#![feature(format_args_capture)]
|
||||
#![cfg_attr(bootstrap, feature(format_args_capture))]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iter_zip)]
|
||||
#![feature(let_else)]
|
||||
|
@ -301,6 +301,8 @@ declare_features! (
|
||||
(accepted, relaxed_struct_unsize, "1.58.0", Some(81793), None),
|
||||
/// Allows dereferencing raw pointers during const eval.
|
||||
(accepted, const_raw_ptr_deref, "1.58.0", Some(51911), None),
|
||||
/// Allows capturing variables in scope using format_args!
|
||||
(accepted, format_args_capture, "1.58.0", Some(67984), None),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: accepted features
|
||||
|
@ -539,9 +539,6 @@ declare_features! (
|
||||
/// Be more precise when looking for live drops in a const context.
|
||||
(active, const_precise_live_drops, "1.46.0", Some(73255), None),
|
||||
|
||||
/// Allows capturing variables in scope using format_args!
|
||||
(active, format_args_capture, "1.46.0", Some(67984), None),
|
||||
|
||||
/// Allows `if let` guard in match arms.
|
||||
(active, if_let_guard, "1.47.0", Some(51114), None),
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
#![feature(bool_to_option)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(format_args_capture)]
|
||||
#![cfg_attr(bootstrap, feature(format_args_capture))]
|
||||
#![feature(iter_order_by)]
|
||||
#![feature(iter_zip)]
|
||||
#![feature(never_type)]
|
||||
|
@ -7,7 +7,7 @@
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(format_args_capture)]
|
||||
#![cfg_attr(bootstrap, feature(format_args_capture))]
|
||||
#![feature(iter_zip)]
|
||||
#![feature(map_try_insert)]
|
||||
#![feature(min_specialization)]
|
||||
|
@ -13,7 +13,7 @@
|
||||
#![feature(drain_filter)]
|
||||
#![feature(bool_to_option)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(format_args_capture)]
|
||||
#![cfg_attr(bootstrap, feature(format_args_capture))]
|
||||
#![feature(iter_zip)]
|
||||
#![feature(let_else)]
|
||||
#![feature(never_type)]
|
||||
|
@ -58,7 +58,7 @@ This API is completely unstable and subject to change.
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![feature(bool_to_option)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(format_args_capture)]
|
||||
#![cfg_attr(bootstrap, feature(format_args_capture))]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(is_sorted)]
|
||||
|
@ -105,7 +105,7 @@
|
||||
#![feature(fmt_internals)]
|
||||
#![feature(fn_traits)]
|
||||
#![feature(inherent_ascii_escape)]
|
||||
#![feature(format_args_capture)]
|
||||
#![cfg_attr(bootstrap, feature(format_args_capture))]
|
||||
#![feature(inplace_iteration)]
|
||||
#![feature(iter_advance_by)]
|
||||
#![feature(iter_zip)]
|
||||
|
@ -1,47 +0,0 @@
|
||||
# `format_args_capture`
|
||||
|
||||
The tracking issue for this feature is: [#67984]
|
||||
|
||||
[#67984]: https://github.com/rust-lang/rust/issues/67984
|
||||
|
||||
------------------------
|
||||
|
||||
Enables `format_args!` (and macros which use `format_args!` in their implementation, such
|
||||
as `format!`, `print!` and `panic!`) to capture variables from the surrounding scope.
|
||||
This avoids the need to pass named parameters when the binding in question
|
||||
already exists in scope.
|
||||
|
||||
```rust
|
||||
#![feature(format_args_capture)]
|
||||
|
||||
let (person, species, name) = ("Charlie Brown", "dog", "Snoopy");
|
||||
|
||||
// captures named argument `person`
|
||||
print!("Hello {person}");
|
||||
|
||||
// captures named arguments `species` and `name`
|
||||
format!("The {species}'s name is {name}.");
|
||||
```
|
||||
|
||||
This also works for formatting parameters such as width and precision:
|
||||
|
||||
```rust
|
||||
#![feature(format_args_capture)]
|
||||
|
||||
let precision = 2;
|
||||
let s = format!("{:.precision$}", 1.324223);
|
||||
|
||||
assert_eq!(&s, "1.32");
|
||||
```
|
||||
|
||||
A non-exhaustive list of macros which benefit from this functionality include:
|
||||
- `format!`
|
||||
- `print!` and `println!`
|
||||
- `eprint!` and `eprintln!`
|
||||
- `write!` and `writeln!`
|
||||
- `panic!`
|
||||
- `unreachable!`
|
||||
- `unimplemented!`
|
||||
- `todo!`
|
||||
- `assert!` and similar
|
||||
- macros in many thirdparty crates, such as `log`
|
@ -1,6 +0,0 @@
|
||||
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`
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
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
|
||||
|
@ -1,5 +1,3 @@
|
||||
#![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`
|
||||
|
@ -1,5 +1,3 @@
|
||||
#![feature(format_args_capture)]
|
||||
|
||||
fn main() {
|
||||
format!("{} {foo} {} {bar} {}", 1, 2, 3);
|
||||
//~^ ERROR: cannot find value `foo` in this scope
|
||||
|
@ -1,5 +1,4 @@
|
||||
// run-pass
|
||||
#![feature(format_args_capture)]
|
||||
#![feature(cfg_panic)]
|
||||
|
||||
fn main() {
|
||||
|
@ -64,7 +64,6 @@ 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
|
||||
@ -72,7 +71,6 @@ error: there is no argument named `bar`
|
||||
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
|
||||
@ -80,7 +78,6 @@ error: there is no argument named `foo`
|
||||
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
|
||||
@ -162,7 +159,6 @@ 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
|
||||
@ -214,7 +210,6 @@ 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
|
||||
|
Loading…
Reference in New Issue
Block a user