Skip to content

Commit eaadb89

Browse files
committed
Auto merge of #100591 - est31:stabilization_placeholder, r=Mark-Simulacrum
Require stabilizations to use a placeholder instead of writing out stabilization version Implements the idea from [this](https://rust-lang.zulipchat.com/#narrow/stream/241545-t-release/topic/libs.20stabilization.20placeholder) zulip stream. It's a common phenomenon that feature stabilizations don't make it into a particular release, but the version is still inaccurate. Often this is caught in the PR, but it can also require subsequent changes to adjust/correct the version. A list with examples of such PRs is given in #100577, but it's far from complete. This PR requires stabilization PRs to use the placeholder `CURRENT_RUSTC_VERSION`, enforced via tidy tooling. The PR also adds a tool that replaces the placeholder with the version number. It can be invoked via `./x.py run src/tools/replace-version-placeholder` and is supposed to be ran upon beta branching as well as version bumping and any backports to the beta branch. I filed PRs to the dev guide and forge to document these changes in the release and stabilization workflows: * The [dev guide](https://rustc-dev-guide.rust-lang.org/stabilization_guide.html#determining-the-stabilization-version) PR: rust-lang/rustc-dev-guide#1443 * The [std dev guide](https://std-dev-guide.rust-lang.org/) PR: rust-lang/std-dev-guide#43 * The [forge](https://github.com/rust-lang/rust-forge) PR: rust-lang/rust-forge#643 Alternative to #100577 which added checking.
2 parents 332cc8f + d32ff14 commit eaadb89

File tree

17 files changed

+271
-86
lines changed

17 files changed

+271
-86
lines changed

Cargo.lock

+8
Original file line numberDiff line numberDiff line change
@@ -3293,6 +3293,14 @@ dependencies = [
32933293
"winapi",
32943294
]
32953295

3296+
[[package]]
3297+
name = "replace-version-placeholder"
3298+
version = "0.1.0"
3299+
dependencies = [
3300+
"tidy",
3301+
"walkdir",
3302+
]
3303+
32963304
[[package]]
32973305
name = "rls"
32983306
version = "1.41.0"

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ members = [
3535
"src/tools/jsondocck",
3636
"src/tools/html-checker",
3737
"src/tools/bump-stage0",
38+
"src/tools/replace-version-placeholder",
3839
"src/tools/lld-wrapper",
3940
]
4041

compiler/rustc_feature/src/accepted.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ declare_features! (
187187
/// especially around globs and shadowing (RFC 1560).
188188
(accepted, item_like_imports, "1.15.0", Some(35120), None),
189189
/// Allows `'a: { break 'a; }`.
190-
(accepted, label_break_value, "1.65.0", Some(48594), None),
190+
(accepted, label_break_value, "CURRENT_RUSTC_VERSION", Some(48594), None),
191191
/// Allows `if/while p && let q = r && ...` chains.
192192
(accepted, let_chains, "1.64.0", Some(53667), None),
193193
/// Allows `break {expr}` with a value inside `loop`s.

compiler/rustc_passes/src/lib_features.rs

+8
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ impl<'tcx> LibFeatureCollector<'tcx> {
5454
}
5555
}
5656
}
57+
const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
58+
59+
if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER {
60+
let version = option_env!("CFG_VERSION").unwrap_or("<current>");
61+
let version = version.split(' ').next().unwrap();
62+
since = Some(Symbol::intern(&version));
63+
}
64+
5765
if let Some(feature) = feature {
5866
// This additional check for stability is to make sure we
5967
// don't emit additional, irrelevant errors for malformed

library/core/src/ptr/const_ptr.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ impl<T: ?Sized> *const T {
9595
///
9696
/// This is a bit safer than `as` because it wouldn't silently change the type if the code is
9797
/// refactored.
98-
#[stable(feature = "ptr_const_cast", since = "1.65.0")]
99-
#[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
98+
#[stable(feature = "ptr_const_cast", since = "CURRENT_RUSTC_VERSION")]
99+
#[rustc_const_stable(feature = "ptr_const_cast", since = "CURRENT_RUSTC_VERSION")]
100100
pub const fn cast_mut(self) -> *mut T {
101101
self as _
102102
}

library/core/src/ptr/mut_ptr.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ impl<T: ?Sized> *mut T {
100100
/// coercion.
101101
///
102102
/// [`cast_mut`]: #method.cast_mut
103-
#[stable(feature = "ptr_const_cast", since = "1.65.0")]
104-
#[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
103+
#[stable(feature = "ptr_const_cast", since = "CURRENT_RUSTC_VERSION")]
104+
#[rustc_const_stable(feature = "ptr_const_cast", since = "CURRENT_RUSTC_VERSION")]
105105
pub const fn cast_const(self) -> *const T {
106106
self as _
107107
}

library/std/src/backtrace.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
//! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime might not actually change
5959
//! how backtraces are captured.
6060
61-
#![stable(feature = "backtrace", since = "1.65.0")]
61+
#![stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
6262

6363
#[cfg(test)]
6464
mod tests;
@@ -104,29 +104,29 @@ use crate::vec::Vec;
104104
/// previous point in time. In some instances the `Backtrace` type may
105105
/// internally be empty due to configuration. For more information see
106106
/// `Backtrace::capture`.
107-
#[stable(feature = "backtrace", since = "1.65.0")]
107+
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
108108
#[must_use]
109109
pub struct Backtrace {
110110
inner: Inner,
111111
}
112112

113113
/// The current status of a backtrace, indicating whether it was captured or
114114
/// whether it is empty for some other reason.
115-
#[stable(feature = "backtrace", since = "1.65.0")]
115+
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
116116
#[non_exhaustive]
117117
#[derive(Debug, PartialEq, Eq)]
118118
pub enum BacktraceStatus {
119119
/// Capturing a backtrace is not supported, likely because it's not
120120
/// implemented for the current platform.
121-
#[stable(feature = "backtrace", since = "1.65.0")]
121+
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
122122
Unsupported,
123123
/// Capturing a backtrace has been disabled through either the
124124
/// `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` environment variables.
125-
#[stable(feature = "backtrace", since = "1.65.0")]
125+
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
126126
Disabled,
127127
/// A backtrace has been captured and the `Backtrace` should print
128128
/// reasonable information when rendered.
129-
#[stable(feature = "backtrace", since = "1.65.0")]
129+
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
130130
Captured,
131131
}
132132

@@ -173,7 +173,7 @@ enum BytesOrWide {
173173
Wide(Vec<u16>),
174174
}
175175

176-
#[stable(feature = "backtrace", since = "1.65.0")]
176+
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
177177
impl fmt::Debug for Backtrace {
178178
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
179179
let capture = match &self.inner {
@@ -289,7 +289,7 @@ impl Backtrace {
289289
///
290290
/// To forcibly capture a backtrace regardless of environment variables, use
291291
/// the `Backtrace::force_capture` function.
292-
#[stable(feature = "backtrace", since = "1.65.0")]
292+
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
293293
#[inline(never)] // want to make sure there's a frame here to remove
294294
pub fn capture() -> Backtrace {
295295
if !Backtrace::enabled() {
@@ -308,16 +308,16 @@ impl Backtrace {
308308
/// Note that capturing a backtrace can be an expensive operation on some
309309
/// platforms, so this should be used with caution in performance-sensitive
310310
/// parts of code.
311-
#[stable(feature = "backtrace", since = "1.65.0")]
311+
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
312312
#[inline(never)] // want to make sure there's a frame here to remove
313313
pub fn force_capture() -> Backtrace {
314314
Backtrace::create(Backtrace::force_capture as usize)
315315
}
316316

317317
/// Forcibly captures a disabled backtrace, regardless of environment
318318
/// variable configuration.
319-
#[stable(feature = "backtrace", since = "1.65.0")]
320-
#[rustc_const_stable(feature = "backtrace", since = "1.65.0")]
319+
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
320+
#[rustc_const_stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
321321
pub const fn disabled() -> Backtrace {
322322
Backtrace { inner: Inner::Disabled }
323323
}
@@ -361,7 +361,7 @@ impl Backtrace {
361361
/// Returns the status of this backtrace, indicating whether this backtrace
362362
/// request was unsupported, disabled, or a stack trace was actually
363363
/// captured.
364-
#[stable(feature = "backtrace", since = "1.65.0")]
364+
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
365365
#[must_use]
366366
pub fn status(&self) -> BacktraceStatus {
367367
match self.inner {
@@ -381,7 +381,7 @@ impl<'a> Backtrace {
381381
}
382382
}
383383

384-
#[stable(feature = "backtrace", since = "1.65.0")]
384+
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
385385
impl fmt::Display for Backtrace {
386386
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
387387
let capture = match &self.inner {

src/bootstrap/builder.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,7 @@ impl<'a> Builder<'a> {
647647
test::CrateRustdocJsonTypes,
648648
test::Linkcheck,
649649
test::TierCheck,
650+
test::ReplacePlaceholderTest,
650651
test::Cargotest,
651652
test::Cargo,
652653
test::Rls,
@@ -746,7 +747,12 @@ impl<'a> Builder<'a> {
746747
install::Src,
747748
install::Rustc
748749
),
749-
Kind::Run => describe!(run::ExpandYamlAnchors, run::BuildManifest, run::BumpStage0),
750+
Kind::Run => describe!(
751+
run::ExpandYamlAnchors,
752+
run::BuildManifest,
753+
run::BumpStage0,
754+
run::ReplaceVersionPlaceholder,
755+
),
750756
// These commands either don't use paths, or they're special-cased in Build::build()
751757
Kind::Clean | Kind::Format | Kind::Setup => vec![],
752758
}

src/bootstrap/run.rs

+22
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,25 @@ impl Step for BumpStage0 {
103103
builder.run(&mut cmd);
104104
}
105105
}
106+
107+
#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
108+
pub struct ReplaceVersionPlaceholder;
109+
110+
impl Step for ReplaceVersionPlaceholder {
111+
type Output = ();
112+
const ONLY_HOSTS: bool = true;
113+
114+
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
115+
run.path("src/tools/replace-version-placeholder")
116+
}
117+
118+
fn make_run(run: RunConfig<'_>) {
119+
run.builder.ensure(ReplaceVersionPlaceholder);
120+
}
121+
122+
fn run(self, builder: &Builder<'_>) -> Self::Output {
123+
let mut cmd = builder.tool_cmd(Tool::ReplaceVersionPlaceholder);
124+
cmd.arg(&builder.src);
125+
builder.run(&mut cmd);
126+
}
127+
}

src/bootstrap/test.rs

+37
Original file line numberDiff line numberDiff line change
@@ -2527,6 +2527,43 @@ impl Step for TierCheck {
25272527
}
25282528
}
25292529

2530+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2531+
pub struct ReplacePlaceholderTest;
2532+
2533+
impl Step for ReplacePlaceholderTest {
2534+
type Output = ();
2535+
const ONLY_HOSTS: bool = true;
2536+
const DEFAULT: bool = true;
2537+
2538+
/// Ensure the version placeholder replacement tool builds
2539+
fn run(self, builder: &Builder<'_>) {
2540+
builder.info("build check for version replacement placeholder");
2541+
2542+
// Test the version placeholder replacement tool itself.
2543+
let bootstrap_host = builder.config.build;
2544+
let compiler = builder.compiler(0, bootstrap_host);
2545+
let cargo = tool::prepare_tool_cargo(
2546+
builder,
2547+
compiler,
2548+
Mode::ToolBootstrap,
2549+
bootstrap_host,
2550+
"test",
2551+
"src/tools/replace-version-placeholder",
2552+
SourceType::InTree,
2553+
&[],
2554+
);
2555+
try_run(builder, &mut cargo.into());
2556+
}
2557+
2558+
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2559+
run.path("src/tools/replace-version-placeholder")
2560+
}
2561+
2562+
fn make_run(run: RunConfig<'_>) {
2563+
run.builder.ensure(Self);
2564+
}
2565+
}
2566+
25302567
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
25312568
pub struct LintDocs {
25322569
pub compiler: Compiler,

src/bootstrap/tool.rs

+1
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,7 @@ bootstrap_tool!(
378378
JsonDocCk, "src/tools/jsondocck", "jsondocck";
379379
HtmlChecker, "src/tools/html-checker", "html-checker";
380380
BumpStage0, "src/tools/bump-stage0", "bump-stage0";
381+
ReplaceVersionPlaceholder, "src/tools/replace-version-placeholder", "replace-version-placeholder";
381382
);
382383

383384
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "replace-version-placeholder"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
tidy = { path = "../tidy" }
10+
walkdir = "2"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use std::path::PathBuf;
2+
use tidy::{t, walk};
3+
4+
pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
5+
6+
fn main() {
7+
let root_path: PathBuf = std::env::args_os().nth(1).expect("need path to root of repo").into();
8+
let version_path = root_path.join("src").join("version");
9+
let version_str = t!(std::fs::read_to_string(&version_path), version_path);
10+
let version_str = version_str.trim();
11+
walk::walk(
12+
&root_path,
13+
&mut |path| {
14+
walk::filter_dirs(path)
15+
// We exempt these as they require the placeholder
16+
// for their operation
17+
|| path.ends_with("compiler/rustc_passes/src/lib_features.rs")
18+
|| path.ends_with("src/tools/tidy/src/features/version.rs")
19+
|| path.ends_with("src/tools/replace-version-placeholder")
20+
},
21+
&mut |entry, contents| {
22+
if !contents.contains(VERSION_PLACEHOLDER) {
23+
return;
24+
}
25+
let new_contents = contents.replace(VERSION_PLACEHOLDER, version_str);
26+
let path = entry.path();
27+
t!(std::fs::write(&path, new_contents), path);
28+
},
29+
);
30+
}

src/tools/tidy/src/features.rs

+38
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,36 @@ pub fn check(
175175
tidy_error!(bad, "Found {} features without a gate test.", gate_untested.len());
176176
}
177177

178+
let (version, channel) = get_version_and_channel(src_path);
179+
180+
let all_features_iter = features
181+
.iter()
182+
.map(|feat| (feat, "lang"))
183+
.chain(lib_features.iter().map(|feat| (feat, "lib")));
184+
for ((feature_name, feature), kind) in all_features_iter {
185+
let since = if let Some(since) = feature.since { since } else { continue };
186+
if since > version && since != Version::CurrentPlaceholder {
187+
tidy_error!(
188+
bad,
189+
"The stabilization version {since} of {kind} feature `{feature_name}` is newer than the current {version}"
190+
);
191+
}
192+
if channel == "nightly" && since == version {
193+
tidy_error!(
194+
bad,
195+
"The stabilization version {since} of {kind} feature `{feature_name}` is written out but should be {}",
196+
version::VERSION_PLACEHOLDER
197+
);
198+
}
199+
if channel != "nightly" && since == Version::CurrentPlaceholder {
200+
tidy_error!(
201+
bad,
202+
"The placeholder use of {kind} feature `{feature_name}` is not allowed on the {} channel",
203+
version::VERSION_PLACEHOLDER
204+
);
205+
}
206+
}
207+
178208
if *bad {
179209
return CollectedFeatures { lib: lib_features, lang: features };
180210
}
@@ -195,6 +225,14 @@ pub fn check(
195225
CollectedFeatures { lib: lib_features, lang: features }
196226
}
197227

228+
fn get_version_and_channel(src_path: &Path) -> (Version, String) {
229+
let version_str = t!(std::fs::read_to_string(src_path.join("version")));
230+
let version_str = version_str.trim();
231+
let version = t!(std::str::FromStr::from_str(&version_str).map_err(|e| format!("{e:?}")));
232+
let channel_str = t!(std::fs::read_to_string(src_path.join("ci").join("channel")));
233+
(version, channel_str.trim().to_owned())
234+
}
235+
198236
fn format_features<'a>(
199237
features: &'a Features,
200238
family: &'a str,

0 commit comments

Comments
 (0)