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: https://github.com/rust-lang/rustc-dev-guide/pull/1443 * The [std dev guide](https://std-dev-guide.rust-lang.org/) PR: https://github.com/rust-lang/std-dev-guide/pull/43 * The [forge](https://github.com/rust-lang/rust-forge) PR: https://github.com/rust-lang/rust-forge/pull/643 Alternative to #100577 which added checking.
This commit is contained in:
commit
eaadb8947b
@ -3293,6 +3293,14 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "replace-version-placeholder"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"tidy",
|
||||||
|
"walkdir",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rls"
|
name = "rls"
|
||||||
version = "1.41.0"
|
version = "1.41.0"
|
||||||
|
@ -35,6 +35,7 @@ members = [
|
|||||||
"src/tools/jsondocck",
|
"src/tools/jsondocck",
|
||||||
"src/tools/html-checker",
|
"src/tools/html-checker",
|
||||||
"src/tools/bump-stage0",
|
"src/tools/bump-stage0",
|
||||||
|
"src/tools/replace-version-placeholder",
|
||||||
"src/tools/lld-wrapper",
|
"src/tools/lld-wrapper",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ declare_features! (
|
|||||||
/// especially around globs and shadowing (RFC 1560).
|
/// especially around globs and shadowing (RFC 1560).
|
||||||
(accepted, item_like_imports, "1.15.0", Some(35120), None),
|
(accepted, item_like_imports, "1.15.0", Some(35120), None),
|
||||||
/// Allows `'a: { break 'a; }`.
|
/// Allows `'a: { break 'a; }`.
|
||||||
(accepted, label_break_value, "1.65.0", Some(48594), None),
|
(accepted, label_break_value, "CURRENT_RUSTC_VERSION", Some(48594), None),
|
||||||
/// Allows `if/while p && let q = r && ...` chains.
|
/// Allows `if/while p && let q = r && ...` chains.
|
||||||
(accepted, let_chains, "1.64.0", Some(53667), None),
|
(accepted, let_chains, "1.64.0", Some(53667), None),
|
||||||
/// Allows `break {expr}` with a value inside `loop`s.
|
/// Allows `break {expr}` with a value inside `loop`s.
|
||||||
|
@ -54,6 +54,14 @@ impl<'tcx> LibFeatureCollector<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
|
||||||
|
|
||||||
|
if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER {
|
||||||
|
let version = option_env!("CFG_VERSION").unwrap_or("<current>");
|
||||||
|
let version = version.split(' ').next().unwrap();
|
||||||
|
since = Some(Symbol::intern(&version));
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(feature) = feature {
|
if let Some(feature) = feature {
|
||||||
// This additional check for stability is to make sure we
|
// This additional check for stability is to make sure we
|
||||||
// don't emit additional, irrelevant errors for malformed
|
// don't emit additional, irrelevant errors for malformed
|
||||||
|
@ -95,8 +95,8 @@ impl<T: ?Sized> *const T {
|
|||||||
///
|
///
|
||||||
/// This is a bit safer than `as` because it wouldn't silently change the type if the code is
|
/// This is a bit safer than `as` because it wouldn't silently change the type if the code is
|
||||||
/// refactored.
|
/// refactored.
|
||||||
#[stable(feature = "ptr_const_cast", since = "1.65.0")]
|
#[stable(feature = "ptr_const_cast", since = "CURRENT_RUSTC_VERSION")]
|
||||||
#[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
|
#[rustc_const_stable(feature = "ptr_const_cast", since = "CURRENT_RUSTC_VERSION")]
|
||||||
pub const fn cast_mut(self) -> *mut T {
|
pub const fn cast_mut(self) -> *mut T {
|
||||||
self as _
|
self as _
|
||||||
}
|
}
|
||||||
|
@ -100,8 +100,8 @@ impl<T: ?Sized> *mut T {
|
|||||||
/// coercion.
|
/// coercion.
|
||||||
///
|
///
|
||||||
/// [`cast_mut`]: #method.cast_mut
|
/// [`cast_mut`]: #method.cast_mut
|
||||||
#[stable(feature = "ptr_const_cast", since = "1.65.0")]
|
#[stable(feature = "ptr_const_cast", since = "CURRENT_RUSTC_VERSION")]
|
||||||
#[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
|
#[rustc_const_stable(feature = "ptr_const_cast", since = "CURRENT_RUSTC_VERSION")]
|
||||||
pub const fn cast_const(self) -> *const T {
|
pub const fn cast_const(self) -> *const T {
|
||||||
self as _
|
self as _
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@
|
|||||||
//! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime might not actually change
|
//! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime might not actually change
|
||||||
//! how backtraces are captured.
|
//! how backtraces are captured.
|
||||||
|
|
||||||
#![stable(feature = "backtrace", since = "1.65.0")]
|
#![stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
@ -104,7 +104,7 @@ use crate::vec::Vec;
|
|||||||
/// previous point in time. In some instances the `Backtrace` type may
|
/// previous point in time. In some instances the `Backtrace` type may
|
||||||
/// internally be empty due to configuration. For more information see
|
/// internally be empty due to configuration. For more information see
|
||||||
/// `Backtrace::capture`.
|
/// `Backtrace::capture`.
|
||||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct Backtrace {
|
pub struct Backtrace {
|
||||||
inner: Inner,
|
inner: Inner,
|
||||||
@ -112,21 +112,21 @@ pub struct Backtrace {
|
|||||||
|
|
||||||
/// The current status of a backtrace, indicating whether it was captured or
|
/// The current status of a backtrace, indicating whether it was captured or
|
||||||
/// whether it is empty for some other reason.
|
/// whether it is empty for some other reason.
|
||||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum BacktraceStatus {
|
pub enum BacktraceStatus {
|
||||||
/// Capturing a backtrace is not supported, likely because it's not
|
/// Capturing a backtrace is not supported, likely because it's not
|
||||||
/// implemented for the current platform.
|
/// implemented for the current platform.
|
||||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||||
Unsupported,
|
Unsupported,
|
||||||
/// Capturing a backtrace has been disabled through either the
|
/// Capturing a backtrace has been disabled through either the
|
||||||
/// `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` environment variables.
|
/// `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` environment variables.
|
||||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||||
Disabled,
|
Disabled,
|
||||||
/// A backtrace has been captured and the `Backtrace` should print
|
/// A backtrace has been captured and the `Backtrace` should print
|
||||||
/// reasonable information when rendered.
|
/// reasonable information when rendered.
|
||||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||||
Captured,
|
Captured,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,7 +173,7 @@ enum BytesOrWide {
|
|||||||
Wide(Vec<u16>),
|
Wide(Vec<u16>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||||
impl fmt::Debug for Backtrace {
|
impl fmt::Debug for Backtrace {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let capture = match &self.inner {
|
let capture = match &self.inner {
|
||||||
@ -289,7 +289,7 @@ impl Backtrace {
|
|||||||
///
|
///
|
||||||
/// To forcibly capture a backtrace regardless of environment variables, use
|
/// To forcibly capture a backtrace regardless of environment variables, use
|
||||||
/// the `Backtrace::force_capture` function.
|
/// the `Backtrace::force_capture` function.
|
||||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||||
#[inline(never)] // want to make sure there's a frame here to remove
|
#[inline(never)] // want to make sure there's a frame here to remove
|
||||||
pub fn capture() -> Backtrace {
|
pub fn capture() -> Backtrace {
|
||||||
if !Backtrace::enabled() {
|
if !Backtrace::enabled() {
|
||||||
@ -308,7 +308,7 @@ impl Backtrace {
|
|||||||
/// Note that capturing a backtrace can be an expensive operation on some
|
/// Note that capturing a backtrace can be an expensive operation on some
|
||||||
/// platforms, so this should be used with caution in performance-sensitive
|
/// platforms, so this should be used with caution in performance-sensitive
|
||||||
/// parts of code.
|
/// parts of code.
|
||||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||||
#[inline(never)] // want to make sure there's a frame here to remove
|
#[inline(never)] // want to make sure there's a frame here to remove
|
||||||
pub fn force_capture() -> Backtrace {
|
pub fn force_capture() -> Backtrace {
|
||||||
Backtrace::create(Backtrace::force_capture as usize)
|
Backtrace::create(Backtrace::force_capture as usize)
|
||||||
@ -316,8 +316,8 @@ impl Backtrace {
|
|||||||
|
|
||||||
/// Forcibly captures a disabled backtrace, regardless of environment
|
/// Forcibly captures a disabled backtrace, regardless of environment
|
||||||
/// variable configuration.
|
/// variable configuration.
|
||||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||||
#[rustc_const_stable(feature = "backtrace", since = "1.65.0")]
|
#[rustc_const_stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||||
pub const fn disabled() -> Backtrace {
|
pub const fn disabled() -> Backtrace {
|
||||||
Backtrace { inner: Inner::Disabled }
|
Backtrace { inner: Inner::Disabled }
|
||||||
}
|
}
|
||||||
@ -361,7 +361,7 @@ impl Backtrace {
|
|||||||
/// Returns the status of this backtrace, indicating whether this backtrace
|
/// Returns the status of this backtrace, indicating whether this backtrace
|
||||||
/// request was unsupported, disabled, or a stack trace was actually
|
/// request was unsupported, disabled, or a stack trace was actually
|
||||||
/// captured.
|
/// captured.
|
||||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn status(&self) -> BacktraceStatus {
|
pub fn status(&self) -> BacktraceStatus {
|
||||||
match self.inner {
|
match self.inner {
|
||||||
@ -381,7 +381,7 @@ impl<'a> Backtrace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "backtrace", since = "1.65.0")]
|
#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
|
||||||
impl fmt::Display for Backtrace {
|
impl fmt::Display for Backtrace {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let capture = match &self.inner {
|
let capture = match &self.inner {
|
||||||
|
@ -647,6 +647,7 @@ impl<'a> Builder<'a> {
|
|||||||
test::CrateRustdocJsonTypes,
|
test::CrateRustdocJsonTypes,
|
||||||
test::Linkcheck,
|
test::Linkcheck,
|
||||||
test::TierCheck,
|
test::TierCheck,
|
||||||
|
test::ReplacePlaceholderTest,
|
||||||
test::Cargotest,
|
test::Cargotest,
|
||||||
test::Cargo,
|
test::Cargo,
|
||||||
test::Rls,
|
test::Rls,
|
||||||
@ -746,7 +747,12 @@ impl<'a> Builder<'a> {
|
|||||||
install::Src,
|
install::Src,
|
||||||
install::Rustc
|
install::Rustc
|
||||||
),
|
),
|
||||||
Kind::Run => describe!(run::ExpandYamlAnchors, run::BuildManifest, run::BumpStage0),
|
Kind::Run => describe!(
|
||||||
|
run::ExpandYamlAnchors,
|
||||||
|
run::BuildManifest,
|
||||||
|
run::BumpStage0,
|
||||||
|
run::ReplaceVersionPlaceholder,
|
||||||
|
),
|
||||||
// These commands either don't use paths, or they're special-cased in Build::build()
|
// These commands either don't use paths, or they're special-cased in Build::build()
|
||||||
Kind::Clean | Kind::Format | Kind::Setup => vec![],
|
Kind::Clean | Kind::Format | Kind::Setup => vec![],
|
||||||
}
|
}
|
||||||
|
@ -103,3 +103,25 @@ impl Step for BumpStage0 {
|
|||||||
builder.run(&mut cmd);
|
builder.run(&mut cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
|
||||||
|
pub struct ReplaceVersionPlaceholder;
|
||||||
|
|
||||||
|
impl Step for ReplaceVersionPlaceholder {
|
||||||
|
type Output = ();
|
||||||
|
const ONLY_HOSTS: bool = true;
|
||||||
|
|
||||||
|
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||||
|
run.path("src/tools/replace-version-placeholder")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_run(run: RunConfig<'_>) {
|
||||||
|
run.builder.ensure(ReplaceVersionPlaceholder);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(self, builder: &Builder<'_>) -> Self::Output {
|
||||||
|
let mut cmd = builder.tool_cmd(Tool::ReplaceVersionPlaceholder);
|
||||||
|
cmd.arg(&builder.src);
|
||||||
|
builder.run(&mut cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2527,6 +2527,43 @@ impl Step for TierCheck {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ReplacePlaceholderTest;
|
||||||
|
|
||||||
|
impl Step for ReplacePlaceholderTest {
|
||||||
|
type Output = ();
|
||||||
|
const ONLY_HOSTS: bool = true;
|
||||||
|
const DEFAULT: bool = true;
|
||||||
|
|
||||||
|
/// Ensure the version placeholder replacement tool builds
|
||||||
|
fn run(self, builder: &Builder<'_>) {
|
||||||
|
builder.info("build check for version replacement placeholder");
|
||||||
|
|
||||||
|
// Test the version placeholder replacement tool itself.
|
||||||
|
let bootstrap_host = builder.config.build;
|
||||||
|
let compiler = builder.compiler(0, bootstrap_host);
|
||||||
|
let cargo = tool::prepare_tool_cargo(
|
||||||
|
builder,
|
||||||
|
compiler,
|
||||||
|
Mode::ToolBootstrap,
|
||||||
|
bootstrap_host,
|
||||||
|
"test",
|
||||||
|
"src/tools/replace-version-placeholder",
|
||||||
|
SourceType::InTree,
|
||||||
|
&[],
|
||||||
|
);
|
||||||
|
try_run(builder, &mut cargo.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||||
|
run.path("src/tools/replace-version-placeholder")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_run(run: RunConfig<'_>) {
|
||||||
|
run.builder.ensure(Self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct LintDocs {
|
pub struct LintDocs {
|
||||||
pub compiler: Compiler,
|
pub compiler: Compiler,
|
||||||
|
@ -378,6 +378,7 @@ bootstrap_tool!(
|
|||||||
JsonDocCk, "src/tools/jsondocck", "jsondocck";
|
JsonDocCk, "src/tools/jsondocck", "jsondocck";
|
||||||
HtmlChecker, "src/tools/html-checker", "html-checker";
|
HtmlChecker, "src/tools/html-checker", "html-checker";
|
||||||
BumpStage0, "src/tools/bump-stage0", "bump-stage0";
|
BumpStage0, "src/tools/bump-stage0", "bump-stage0";
|
||||||
|
ReplaceVersionPlaceholder, "src/tools/replace-version-placeholder", "replace-version-placeholder";
|
||||||
);
|
);
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
|
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
|
||||||
|
10
src/tools/replace-version-placeholder/Cargo.toml
Normal file
10
src/tools/replace-version-placeholder/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "replace-version-placeholder"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tidy = { path = "../tidy" }
|
||||||
|
walkdir = "2"
|
30
src/tools/replace-version-placeholder/src/main.rs
Normal file
30
src/tools/replace-version-placeholder/src/main.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
use tidy::{t, walk};
|
||||||
|
|
||||||
|
pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let root_path: PathBuf = std::env::args_os().nth(1).expect("need path to root of repo").into();
|
||||||
|
let version_path = root_path.join("src").join("version");
|
||||||
|
let version_str = t!(std::fs::read_to_string(&version_path), version_path);
|
||||||
|
let version_str = version_str.trim();
|
||||||
|
walk::walk(
|
||||||
|
&root_path,
|
||||||
|
&mut |path| {
|
||||||
|
walk::filter_dirs(path)
|
||||||
|
// We exempt these as they require the placeholder
|
||||||
|
// for their operation
|
||||||
|
|| path.ends_with("compiler/rustc_passes/src/lib_features.rs")
|
||||||
|
|| path.ends_with("src/tools/tidy/src/features/version.rs")
|
||||||
|
|| path.ends_with("src/tools/replace-version-placeholder")
|
||||||
|
},
|
||||||
|
&mut |entry, contents| {
|
||||||
|
if !contents.contains(VERSION_PLACEHOLDER) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let new_contents = contents.replace(VERSION_PLACEHOLDER, version_str);
|
||||||
|
let path = entry.path();
|
||||||
|
t!(std::fs::write(&path, new_contents), path);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
@ -175,6 +175,36 @@ pub fn check(
|
|||||||
tidy_error!(bad, "Found {} features without a gate test.", gate_untested.len());
|
tidy_error!(bad, "Found {} features without a gate test.", gate_untested.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (version, channel) = get_version_and_channel(src_path);
|
||||||
|
|
||||||
|
let all_features_iter = features
|
||||||
|
.iter()
|
||||||
|
.map(|feat| (feat, "lang"))
|
||||||
|
.chain(lib_features.iter().map(|feat| (feat, "lib")));
|
||||||
|
for ((feature_name, feature), kind) in all_features_iter {
|
||||||
|
let since = if let Some(since) = feature.since { since } else { continue };
|
||||||
|
if since > version && since != Version::CurrentPlaceholder {
|
||||||
|
tidy_error!(
|
||||||
|
bad,
|
||||||
|
"The stabilization version {since} of {kind} feature `{feature_name}` is newer than the current {version}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if channel == "nightly" && since == version {
|
||||||
|
tidy_error!(
|
||||||
|
bad,
|
||||||
|
"The stabilization version {since} of {kind} feature `{feature_name}` is written out but should be {}",
|
||||||
|
version::VERSION_PLACEHOLDER
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if channel != "nightly" && since == Version::CurrentPlaceholder {
|
||||||
|
tidy_error!(
|
||||||
|
bad,
|
||||||
|
"The placeholder use of {kind} feature `{feature_name}` is not allowed on the {} channel",
|
||||||
|
version::VERSION_PLACEHOLDER
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if *bad {
|
if *bad {
|
||||||
return CollectedFeatures { lib: lib_features, lang: features };
|
return CollectedFeatures { lib: lib_features, lang: features };
|
||||||
}
|
}
|
||||||
@ -195,6 +225,14 @@ pub fn check(
|
|||||||
CollectedFeatures { lib: lib_features, lang: features }
|
CollectedFeatures { lib: lib_features, lang: features }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_version_and_channel(src_path: &Path) -> (Version, String) {
|
||||||
|
let version_str = t!(std::fs::read_to_string(src_path.join("version")));
|
||||||
|
let version_str = version_str.trim();
|
||||||
|
let version = t!(std::str::FromStr::from_str(&version_str).map_err(|e| format!("{e:?}")));
|
||||||
|
let channel_str = t!(std::fs::read_to_string(src_path.join("ci").join("channel")));
|
||||||
|
(version, channel_str.trim().to_owned())
|
||||||
|
}
|
||||||
|
|
||||||
fn format_features<'a>(
|
fn format_features<'a>(
|
||||||
features: &'a Features,
|
features: &'a Features,
|
||||||
family: &'a str,
|
family: &'a str,
|
||||||
|
@ -5,14 +5,22 @@ use std::str::FromStr;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
|
pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Version {
|
pub enum Version {
|
||||||
parts: [u32; 3],
|
Explicit { parts: [u32; 3] },
|
||||||
|
CurrentPlaceholder,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Version {
|
impl fmt::Display for Version {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.pad(&format!("{}.{}.{}", self.parts[0], self.parts[1], self.parts[2]))
|
match self {
|
||||||
|
Version::Explicit { parts } => {
|
||||||
|
f.pad(&format!("{}.{}.{}", parts[0], parts[1], parts[2]))
|
||||||
|
}
|
||||||
|
Version::CurrentPlaceholder => f.pad(&format!("CURRENT")),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,6 +40,9 @@ impl FromStr for Version {
|
|||||||
type Err = ParseVersionError;
|
type Err = ParseVersionError;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
if s == VERSION_PLACEHOLDER {
|
||||||
|
return Ok(Version::CurrentPlaceholder);
|
||||||
|
}
|
||||||
let mut iter = s.split('.').map(|part| Ok(part.parse()?));
|
let mut iter = s.split('.').map(|part| Ok(part.parse()?));
|
||||||
|
|
||||||
let mut part = || iter.next().unwrap_or(Err(ParseVersionError::WrongNumberOfParts));
|
let mut part = || iter.next().unwrap_or(Err(ParseVersionError::WrongNumberOfParts));
|
||||||
@ -43,6 +54,6 @@ impl FromStr for Version {
|
|||||||
return Err(ParseVersionError::WrongNumberOfParts);
|
return Err(ParseVersionError::WrongNumberOfParts);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self { parts })
|
Ok(Version::Explicit { parts })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,14 @@
|
|||||||
//! This library contains the tidy lints and exposes it
|
//! This library contains the tidy lints and exposes it
|
||||||
//! to be used by tools.
|
//! to be used by tools.
|
||||||
|
|
||||||
use std::fs::File;
|
use walk::{filter_dirs, walk, walk_many, walk_no_read};
|
||||||
use std::io::Read;
|
|
||||||
use walkdir::{DirEntry, WalkDir};
|
|
||||||
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
|
/// A helper macro to `unwrap` a result except also print out details like:
|
||||||
|
///
|
||||||
|
/// * The expression that failed
|
||||||
|
/// * The error itself
|
||||||
|
/// * (optionally) a path connected to the error (e.g. failure to open a file)
|
||||||
|
#[macro_export]
|
||||||
macro_rules! t {
|
macro_rules! t {
|
||||||
($e:expr, $p:expr) => {
|
($e:expr, $p:expr) => {
|
||||||
match $e {
|
match $e {
|
||||||
@ -28,7 +30,8 @@ macro_rules! t {
|
|||||||
macro_rules! tidy_error {
|
macro_rules! tidy_error {
|
||||||
($bad:expr, $fmt:expr) => ({
|
($bad:expr, $fmt:expr) => ({
|
||||||
*$bad = true;
|
*$bad = true;
|
||||||
eprintln!("tidy error: {}", $fmt);
|
eprint!("tidy error: ");
|
||||||
|
eprintln!($fmt);
|
||||||
});
|
});
|
||||||
($bad:expr, $fmt:expr, $($arg:tt)*) => ({
|
($bad:expr, $fmt:expr, $($arg:tt)*) => ({
|
||||||
*$bad = true;
|
*$bad = true;
|
||||||
@ -52,59 +55,4 @@ pub mod target_specific_tests;
|
|||||||
pub mod ui_tests;
|
pub mod ui_tests;
|
||||||
pub mod unit_tests;
|
pub mod unit_tests;
|
||||||
pub mod unstable_book;
|
pub mod unstable_book;
|
||||||
|
pub mod walk;
|
||||||
fn filter_dirs(path: &Path) -> bool {
|
|
||||||
let skip = [
|
|
||||||
"tidy-test-file",
|
|
||||||
"compiler/rustc_codegen_cranelift",
|
|
||||||
"compiler/rustc_codegen_gcc",
|
|
||||||
"src/llvm-project",
|
|
||||||
"library/backtrace",
|
|
||||||
"library/portable-simd",
|
|
||||||
"library/stdarch",
|
|
||||||
"src/tools/cargo",
|
|
||||||
"src/tools/clippy",
|
|
||||||
"src/tools/miri",
|
|
||||||
"src/tools/rls",
|
|
||||||
"src/tools/rust-analyzer",
|
|
||||||
"src/tools/rust-installer",
|
|
||||||
"src/tools/rustfmt",
|
|
||||||
"src/doc/book",
|
|
||||||
// Filter RLS output directories
|
|
||||||
"target/rls",
|
|
||||||
];
|
|
||||||
skip.iter().any(|p| path.ends_with(p))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn walk_many(
|
|
||||||
paths: &[&Path],
|
|
||||||
skip: &mut dyn FnMut(&Path) -> bool,
|
|
||||||
f: &mut dyn FnMut(&DirEntry, &str),
|
|
||||||
) {
|
|
||||||
for path in paths {
|
|
||||||
walk(path, skip, f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn walk(path: &Path, skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry, &str)) {
|
|
||||||
let mut contents = String::new();
|
|
||||||
walk_no_read(path, skip, &mut |entry| {
|
|
||||||
contents.clear();
|
|
||||||
if t!(File::open(entry.path()), entry.path()).read_to_string(&mut contents).is_err() {
|
|
||||||
contents.clear();
|
|
||||||
}
|
|
||||||
f(&entry, &contents);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn walk_no_read(path: &Path, skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry)) {
|
|
||||||
let walker = WalkDir::new(path).into_iter().filter_entry(|e| !skip(e.path()));
|
|
||||||
for entry in walker {
|
|
||||||
if let Ok(entry) = entry {
|
|
||||||
if entry.file_type().is_dir() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
f(&entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
65
src/tools/tidy/src/walk.rs
Normal file
65
src/tools/tidy/src/walk.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
use walkdir::{DirEntry, WalkDir};
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
pub fn filter_dirs(path: &Path) -> bool {
|
||||||
|
let skip = [
|
||||||
|
"tidy-test-file",
|
||||||
|
"compiler/rustc_codegen_cranelift",
|
||||||
|
"compiler/rustc_codegen_gcc",
|
||||||
|
"src/llvm-project",
|
||||||
|
"library/backtrace",
|
||||||
|
"library/portable-simd",
|
||||||
|
"library/stdarch",
|
||||||
|
"src/tools/cargo",
|
||||||
|
"src/tools/clippy",
|
||||||
|
"src/tools/miri",
|
||||||
|
"src/tools/rls",
|
||||||
|
"src/tools/rust-analyzer",
|
||||||
|
"src/tools/rust-installer",
|
||||||
|
"src/tools/rustfmt",
|
||||||
|
"src/doc/book",
|
||||||
|
// Filter RLS output directories
|
||||||
|
"target/rls",
|
||||||
|
];
|
||||||
|
skip.iter().any(|p| path.ends_with(p))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk_many(
|
||||||
|
paths: &[&Path],
|
||||||
|
skip: &mut dyn FnMut(&Path) -> bool,
|
||||||
|
f: &mut dyn FnMut(&DirEntry, &str),
|
||||||
|
) {
|
||||||
|
for path in paths {
|
||||||
|
walk(path, skip, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk(path: &Path, skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry, &str)) {
|
||||||
|
let mut contents = String::new();
|
||||||
|
walk_no_read(path, skip, &mut |entry| {
|
||||||
|
contents.clear();
|
||||||
|
if t!(File::open(entry.path()), entry.path()).read_to_string(&mut contents).is_err() {
|
||||||
|
contents.clear();
|
||||||
|
}
|
||||||
|
f(&entry, &contents);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn walk_no_read(
|
||||||
|
path: &Path,
|
||||||
|
skip: &mut dyn FnMut(&Path) -> bool,
|
||||||
|
f: &mut dyn FnMut(&DirEntry),
|
||||||
|
) {
|
||||||
|
let walker = WalkDir::new(path).into_iter().filter_entry(|e| !skip(e.path()));
|
||||||
|
for entry in walker {
|
||||||
|
if let Ok(entry) = entry {
|
||||||
|
if entry.file_type().is_dir() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
f(&entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user