From 8c9bfaa5f3a1a0bd487d0a6908492d56923d72a8 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 1 Nov 2021 16:18:36 +0100 Subject: [PATCH] Stabilize format_args_capture Works as expected, and there are widespread reports of success with it, as well as interest in it. --- compiler/rustc_borrowck/src/lib.rs | 2 +- compiler/rustc_builtin_macros/src/format.rs | 36 ++++---------- compiler/rustc_errors/src/lib.rs | 2 +- compiler/rustc_expand/src/lib.rs | 2 +- compiler/rustc_feature/src/accepted.rs | 2 + compiler/rustc_feature/src/active.rs | 3 -- compiler/rustc_lint/src/lib.rs | 2 +- compiler/rustc_passes/src/lib.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 2 +- compiler/rustc_typeck/src/lib.rs | 2 +- library/alloc/src/lib.rs | 2 +- .../library-features/format-args-capture.md | 47 ------------------- .../fmt/feature-gate-format-args-capture.rs | 6 --- .../feature-gate-format-args-capture.stderr | 18 ------- .../fmt/format-args-capture-macro-hygiene.rs | 2 - .../format-args-capture-missing-variables.rs | 2 - src/test/ui/fmt/format-args-capture.rs | 1 - src/test/ui/fmt/ifmt-bad-arg.stderr | 5 -- 18 files changed, 20 insertions(+), 118 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/format-args-capture.md delete mode 100644 src/test/ui/fmt/feature-gate-format-args-capture.rs delete mode 100644 src/test/ui/fmt/feature-gate-format-args-capture.stderr diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index aca7d3174f6..76d3a83b48d 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -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)] diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 52b00a2bc74..097eaddb874 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -527,17 +527,9 @@ fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) { 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 @@ fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) { }; 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(); } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 21a2eb771c8..bb3d3a415e7 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -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)] diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 521ca2135c6..4e84a9df6c9 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -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)] diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 3bd1272c7cb..3cb543fe3ab 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -301,6 +301,8 @@ macro_rules! 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 diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index d8b4539d831..61dd505e1e9 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -539,9 +539,6 @@ pub fn set(&self, features: &mut Features, span: Span) { /// 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), diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index f6514ddca9f..507b4421fa1 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -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)] diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 4adec3c4f60..af1c7244100 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -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)] diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index f5bea83bdcf..d17e8875a1e 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -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)] diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index ba0fd12a275..0881cf07586 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -58,7 +58,7 @@ #![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)] diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 746dd50ad22..4a66c3f6b2e 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -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)] diff --git a/src/doc/unstable-book/src/library-features/format-args-capture.md b/src/doc/unstable-book/src/library-features/format-args-capture.md deleted file mode 100644 index 64b1b3d81bd..00000000000 --- a/src/doc/unstable-book/src/library-features/format-args-capture.md +++ /dev/null @@ -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` diff --git a/src/test/ui/fmt/feature-gate-format-args-capture.rs b/src/test/ui/fmt/feature-gate-format-args-capture.rs deleted file mode 100644 index 21af9161091..00000000000 --- a/src/test/ui/fmt/feature-gate-format-args-capture.rs +++ /dev/null @@ -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` -} diff --git a/src/test/ui/fmt/feature-gate-format-args-capture.stderr b/src/test/ui/fmt/feature-gate-format-args-capture.stderr deleted file mode 100644 index f08f1651cb6..00000000000 --- a/src/test/ui/fmt/feature-gate-format-args-capture.stderr +++ /dev/null @@ -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 - diff --git a/src/test/ui/fmt/format-args-capture-macro-hygiene.rs b/src/test/ui/fmt/format-args-capture-macro-hygiene.rs index 6ca7dcc216f..fdbd93836ef 100644 --- a/src/test/ui/fmt/format-args-capture-macro-hygiene.rs +++ b/src/test/ui/fmt/format-args-capture-macro-hygiene.rs @@ -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` diff --git a/src/test/ui/fmt/format-args-capture-missing-variables.rs b/src/test/ui/fmt/format-args-capture-missing-variables.rs index 3a4b6144b04..46fc083cb73 100644 --- a/src/test/ui/fmt/format-args-capture-missing-variables.rs +++ b/src/test/ui/fmt/format-args-capture-missing-variables.rs @@ -1,5 +1,3 @@ -#![feature(format_args_capture)] - fn main() { format!("{} {foo} {} {bar} {}", 1, 2, 3); //~^ ERROR: cannot find value `foo` in this scope diff --git a/src/test/ui/fmt/format-args-capture.rs b/src/test/ui/fmt/format-args-capture.rs index b30e9a47a13..e830a5bc9c5 100644 --- a/src/test/ui/fmt/format-args-capture.rs +++ b/src/test/ui/fmt/format-args-capture.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(format_args_capture)] #![feature(cfg_panic)] fn main() { diff --git a/src/test/ui/fmt/ifmt-bad-arg.stderr b/src/test/ui/fmt/ifmt-bad-arg.stderr index f4c84e22faa..a6c7aa33e29 100644 --- a/src/test/ui/fmt/ifmt-bad-arg.stderr +++ b/src/test/ui/fmt/ifmt-bad-arg.stderr @@ -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 -- 2.44.0