From 625f64e003710ad26d3f13c2a15c2a9823ad5f5c Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 14 Apr 2026 06:19:25 +0000 Subject: [PATCH 1/6] add & use emit_unstable_feature in main lib --- build.rs | 28 ++++++++++++++++++++++++++++ src/lib.rs | 4 ++-- tests/test_usage.rs | 2 +- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/build.rs b/build.rs index 129592d..b666ef1 100644 --- a/build.rs +++ b/build.rs @@ -4,15 +4,43 @@ extern crate autocfg; fn main() { let ac = autocfg::new(); + ac.emit_unstable_feature("assert_matches"); stable_feature(&ac, "assert_matches"); assert_matches_in_module(&ac); assert_matches_in_root(&ac); + ac.emit_unstable_feature("let_chains"); stable_feature(&ac, "let_chains"); + ac.emit_unstable_feature("if_let_guard"); stable_feature(&ac, "if_let_guard"); } +trait UnstableFeature { + /// Identify whether a an experimental feature flag is available _and_ required on nightly. + /// Always fails if feature flags are unavailable. + /// + /// ## Usage: + /// To be used at top-level crate via `#![cfg_attr(unstable_foo, feature(foo))]` + fn emit_unstable_feature(&self, feature: &'static str); +} + +impl UnstableFeature for AutoCfg { + fn emit_unstable_feature(&self, feature: &'static str) { + let cfg = format!("unstable_{feature}"); + let code = format!( + r#" + #![deny(stable_features)] + #![feature({feature})] + "# + ); + autocfg::emit_possibility(&cfg); + if self.probe_raw(&code).is_ok() { + autocfg::emit(&cfg); + } + } +} + fn stable_feature(ac: &AutoCfg, feature: &'static str) { let cfg = format!("stable_{feature}"); let deny = format!( diff --git a/src/lib.rs b/src/lib.rs index a98c4af..6e8601c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ -#![cfg_attr(not(stable_if_let_guard), feature(if_let_guard))] -#![cfg_attr(not(stable_let_chains), feature(let_chains))] +#![cfg_attr(unstable_if_let_guard, feature(if_let_guard))] +#![cfg_attr(unstable_let_chains, feature(let_chains))] #![feature(never_type)] //! Provides a derive macro for [Try] & optionally [Try_ConvertResult] for interconversion with diff --git a/tests/test_usage.rs b/tests/test_usage.rs index 0cd4d90..f3b0605 100644 --- a/tests/test_usage.rs +++ b/tests/test_usage.rs @@ -1,4 +1,4 @@ -#![cfg_attr(not(stable_assert_matches), feature(assert_matches))] +#![cfg_attr(unstable_assert_matches, feature(assert_matches))] #![feature(iterator_try_collect)] #![feature(never_type)] #![feature(try_trait_v2)] From ef419362209b64181fa56f0cb6d2f6c7734212e3 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 14 Apr 2026 06:55:49 +0000 Subject: [PATCH 2/6] remove stable_feature --- build.rs | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/build.rs b/build.rs index b666ef1..36888fb 100644 --- a/build.rs +++ b/build.rs @@ -5,15 +5,12 @@ extern crate autocfg; fn main() { let ac = autocfg::new(); ac.emit_unstable_feature("assert_matches"); - stable_feature(&ac, "assert_matches"); assert_matches_in_module(&ac); assert_matches_in_root(&ac); ac.emit_unstable_feature("let_chains"); - stable_feature(&ac, "let_chains"); ac.emit_unstable_feature("if_let_guard"); - stable_feature(&ac, "if_let_guard"); } trait UnstableFeature { @@ -40,29 +37,6 @@ impl UnstableFeature for AutoCfg { } } } - -fn stable_feature(ac: &AutoCfg, feature: &'static str) { - let cfg = format!("stable_{feature}"); - let deny = format!( - r#" - #![deny(stable_features)] - #![feature({feature})] - "# - ); - - let allow = format!( - r#" - #![allow(stable_features)] - #![feature({feature})] - "# - ); - - autocfg::emit_possibility(&cfg); - if ac.probe_raw(&deny).is_err() && ac.probe_raw(&allow).is_ok() { - autocfg::emit(&cfg); - } -} - fn assert_matches_in_root(ac: &AutoCfg) { let cfg = "assert_matches_in_root"; let code = r#" From f6a5385a53a23d49a902822e3165050d768be6ca Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 14 Apr 2026 06:56:08 +0000 Subject: [PATCH 3/6] rename trait to nightly --- build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.rs b/build.rs index 36888fb..b8ee742 100644 --- a/build.rs +++ b/build.rs @@ -13,7 +13,7 @@ fn main() { ac.emit_unstable_feature("if_let_guard"); } -trait UnstableFeature { +trait Nightly { /// Identify whether a an experimental feature flag is available _and_ required on nightly. /// Always fails if feature flags are unavailable. /// @@ -22,7 +22,7 @@ trait UnstableFeature { fn emit_unstable_feature(&self, feature: &'static str); } -impl UnstableFeature for AutoCfg { +impl Nightly for AutoCfg { fn emit_unstable_feature(&self, feature: &'static str) { let cfg = format!("unstable_{feature}"); let code = format!( From 6efe60d85642dd027b3e8014375aa445a394f22c Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 14 Apr 2026 07:32:44 +0000 Subject: [PATCH 4/6] move assert_matches location checks to nightly trait --- build.rs | 93 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 32 deletions(-) diff --git a/build.rs b/build.rs index b8ee742..23e7be9 100644 --- a/build.rs +++ b/build.rs @@ -1,18 +1,46 @@ +use std::fmt::Display; + use autocfg::AutoCfg; extern crate autocfg; fn main() { let ac = autocfg::new(); + ac.emit_unstable_feature("assert_matches"); - assert_matches_in_module(&ac); - assert_matches_in_root(&ac); + AssertMatchesLocation::emit_possibilities(); + if let Some(location) = ac.assert_matches_location() { + autocfg::emit(&location.to_string()) + } ac.emit_unstable_feature("let_chains"); ac.emit_unstable_feature("if_let_guard"); } +enum AssertMatchesLocation { + /// Macro is at `std::assert_matches` + Root, + /// Macro is at `std::assert_matches::assert_matches` + Module, +} + +impl Display for AssertMatchesLocation { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + AssertMatchesLocation::Root => write!(f, "assert_matches_in_root"), + AssertMatchesLocation::Module => write!(f, "assert_matches_in_module"), + } + } +} + +impl AssertMatchesLocation { + fn emit_possibilities() { + autocfg::emit_possibility("assert_matches_in_root"); + autocfg::emit_possibility("assert_matches_in_module"); + } +} + trait Nightly { /// Identify whether a an experimental feature flag is available _and_ required on nightly. /// Always fails if feature flags are unavailable. @@ -20,6 +48,10 @@ trait Nightly { /// ## Usage: /// To be used at top-level crate via `#![cfg_attr(unstable_foo, feature(foo))]` fn emit_unstable_feature(&self, feature: &'static str); + + /// Location of assert_matches!() macro. Stabilisation was reverted at last minute + /// on 2026-04-10, leaving the macro in the new planned location. + fn assert_matches_location(&self) -> Option; } impl Nightly for AutoCfg { @@ -36,37 +68,34 @@ impl Nightly for AutoCfg { autocfg::emit(&cfg); } } -} -fn assert_matches_in_root(ac: &AutoCfg) { - let cfg = "assert_matches_in_root"; - let code = r#" - #![allow(stable_features)] - #![feature(assert_matches)] - use std::assert_matches; - - fn main() { - assert_matches!(Some(4), Some(_)); - } - "#; - autocfg::emit_possibility(cfg); - if ac.probe_raw(code).is_ok() { - autocfg::emit(cfg); - } -} -fn assert_matches_in_module(ac: &AutoCfg) { - let cfg = "assert_matches_in_module"; - let code = r#" - #![allow(stable_features)] - #![feature(assert_matches)] - use std::assert_matches::assert_matches; + fn assert_matches_location(&self) -> Option { + let in_root = r#" + #![allow(stable_features)] + #![feature(assert_matches)] + use std::assert_matches; - fn main() { - assert_matches!(Some(4), Some(_)); - } - "#; - autocfg::emit_possibility(cfg); - if ac.probe_raw(code).is_ok() { - autocfg::emit(cfg); + fn main() { + assert_matches!(Some(4), Some(_)); + } + "#; + + let in_module = r#" + #![allow(stable_features)] + #![feature(assert_matches)] + use std::assert_matches::assert_matches; + + fn main() { + assert_matches!(Some(4), Some(_)); + } + "#; + + if self.probe_raw(in_root).is_ok() { + Some(AssertMatchesLocation::Root) + } else if self.probe_raw(in_module).is_ok() { + Some(AssertMatchesLocation::Module) + } else { + None + } } } From 34c859c103be17bb74faedd0e45af5adcf84fc59 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 14 Apr 2026 07:34:33 +0000 Subject: [PATCH 5/6] document assert_matches checks --- build.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/build.rs b/build.rs index 23e7be9..08df029 100644 --- a/build.rs +++ b/build.rs @@ -18,6 +18,8 @@ fn main() { ac.emit_unstable_feature("if_let_guard"); } +/// Location of assert_matches!() macro. Stabilisation was reverted at last minute +/// on 2026-04-10, leaving the macro in the new planned location. enum AssertMatchesLocation { /// Macro is at `std::assert_matches` Root, @@ -51,6 +53,14 @@ trait Nightly { /// Location of assert_matches!() macro. Stabilisation was reverted at last minute /// on 2026-04-10, leaving the macro in the new planned location. + /// + /// #Recommended usage + /// ``` + /// AssertMatchesLocation::emit_possibilities(); + /// if let Some(location) = ac.assert_matches_location() { + /// autocfg::emit(&location.to_string()) + /// } + /// ``` fn assert_matches_location(&self) -> Option; } From 0fb21c258216e685065d3ffa0bef96ff1b9935b4 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 14 Apr 2026 07:40:20 +0000 Subject: [PATCH 6/6] avoid duplicating cfg keys for AssertMatchesLocation --- build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.rs b/build.rs index 08df029..56d1b88 100644 --- a/build.rs +++ b/build.rs @@ -38,8 +38,8 @@ impl Display for AssertMatchesLocation { impl AssertMatchesLocation { fn emit_possibilities() { - autocfg::emit_possibility("assert_matches_in_root"); - autocfg::emit_possibility("assert_matches_in_module"); + autocfg::emit_possibility(&AssertMatchesLocation::Root.to_string()); + autocfg::emit_possibility(&AssertMatchesLocation::Module.to_string()); } }