From 966f4b3b0c906838e689a438a06b9ade4f839e5c Mon Sep 17 00:00:00 2001 From: Henry Jiang Date: Tue, 5 Nov 2024 12:58:37 -0500 Subject: [PATCH 01/20] add run-make support for aix --- src/tools/compiletest/src/directive-list.rs | 1 + src/tools/run-make-support/src/external_deps/rustc.rs | 5 ++++- src/tools/run-make-support/src/targets.rs | 6 ++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs index 980b3f6829a..446e90978f6 100644 --- a/src/tools/compiletest/src/directive-list.rs +++ b/src/tools/compiletest/src/directive-list.rs @@ -35,6 +35,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-64bit", "ignore-aarch64", "ignore-aarch64-unknown-linux-gnu", + "ignore-aix", "ignore-android", "ignore-apple", "ignore-arm", diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index 35d983dc607..c2989aedee1 100644 --- a/src/tools/run-make-support/src/external_deps/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -5,7 +5,7 @@ use crate::command::Command; use crate::env::env_var; use crate::path_helpers::cwd; use crate::util::set_host_rpath; -use crate::{is_darwin, is_msvc, is_windows, uname}; +use crate::{is_aix, is_darwin, is_msvc, is_windows, uname}; /// Construct a new `rustc` invocation. This will automatically set the library /// search path as `-L cwd()`. Use [`bare_rustc`] to avoid this. @@ -365,6 +365,9 @@ impl Rustc { if is_msvc() { None } else { Some("-lstatic:-bundle=stdc++") } } else if is_darwin() { Some("-lc++") + } else if is_aix() { + self.cmd.arg("-lc++"); + Some("-lc++abi") } else { match &uname()[..] { "FreeBSD" | "SunOS" | "OpenBSD" => None, diff --git a/src/tools/run-make-support/src/targets.rs b/src/tools/run-make-support/src/targets.rs index 896abb73fc1..ae004fd0cbd 100644 --- a/src/tools/run-make-support/src/targets.rs +++ b/src/tools/run-make-support/src/targets.rs @@ -28,6 +28,12 @@ pub fn is_darwin() -> bool { target().contains("darwin") } +/// Check if target uses AIX. +#[must_use] +pub fn is_aix() -> bool { + target().contains("aix") +} + /// Get the target OS on Apple operating systems. #[must_use] pub fn apple_os() -> &'static str { From 904e897d07b848d8e17e7addb40bc56fb58cd2ec Mon Sep 17 00:00:00 2001 From: Henry Jiang Date: Tue, 5 Nov 2024 14:21:08 -0500 Subject: [PATCH 02/20] fix missing use decl --- src/tools/run-make-support/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 368b98c9f0d..1b2fd6cbe06 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -77,7 +77,7 @@ pub use env::{env_var, env_var_os, set_current_dir}; pub use run::{cmd, run, run_fail, run_with_args}; /// Helpers for checking target information. -pub use targets::{is_darwin, is_msvc, is_windows, llvm_components_contain, target, uname, apple_os}; +pub use targets::{is_aix, is_darwin, is_msvc, is_windows, llvm_components_contain, target, uname, apple_os}; /// Helpers for building names of output artifacts that are potentially target-specific. pub use artifact_names::{ From 686eeb83e9c6d7f70848cdf84f490f5c1aa3edd3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Nov 2024 20:15:18 +0100 Subject: [PATCH 03/20] honor rustc_const_stable_indirect in non-staged_api crate with -Zforce-unstable-if-unmarked --- compiler/rustc_attr/src/builtin.rs | 20 ++++++++++ .../rustc_const_eval/src/check_consts/mod.rs | 7 ++-- compiler/rustc_passes/src/stability.rs | 5 +++ library/std/src/lib.rs | 5 +++ .../auxiliary/unmarked_const_fn_crate.rs | 1 + .../unstable_if_unmarked_const_fn_crate.rs | 8 ++++ ...rsive_const_stab_unmarked_crate_imports.rs | 23 ++++++++++++ ...e_const_stab_unmarked_crate_imports.stderr | 28 ++++++++++++++ ...cursive_const_stab_unstable_if_unmarked.rs | 24 ++++++++++++ ...ive_const_stab_unstable_if_unmarked.stderr | 37 +++++++++++++++++++ 10 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 tests/ui/consts/min_const_fn/auxiliary/unmarked_const_fn_crate.rs create mode 100644 tests/ui/consts/min_const_fn/auxiliary/unstable_if_unmarked_const_fn_crate.rs create mode 100644 tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.rs create mode 100644 tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.stderr create mode 100644 tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.rs create mode 100644 tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.stderr diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 2753ac529d1..3a7ea36f601 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -381,6 +381,26 @@ pub fn find_const_stability( const_stab } +/// Calculates the const stability for a const function in a `-Zforce-unstable-if-unmarked` crate +/// without the `staged_api` feature. +pub fn unmarked_crate_const_stab( + _sess: &Session, + attrs: &[Attribute], + regular_stab: Stability, +) -> ConstStability { + assert!(regular_stab.level.is_unstable()); + // The only attribute that matters here is `rustc_const_stable_indirect`. + // We enforce recursive const stability rules for those functions. + let const_stable_indirect = + attrs.iter().any(|a| a.name_or_empty() == sym::rustc_const_stable_indirect); + ConstStability { + feature: Some(regular_stab.feature), + const_stable_indirect, + promotable: false, + level: regular_stab.level, + } +} + /// Collects stability info from `rustc_default_body_unstable` attributes in `attrs`. /// Returns `None` if no stability attributes are found. pub fn find_body_stability( diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index dcdaafaecc2..3b2a79793ae 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -53,10 +53,11 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> { } pub fn enforce_recursive_const_stability(&self) -> bool { - // We can skip this if `staged_api` is not enabled, since in such crates - // `lookup_const_stability` will always be `None`. + // We can skip this if neither `staged_api` nor `-Zforrce-unstable-if-unmarked` are enabled, + // since in such crates `lookup_const_stability` will always be `None`. self.const_kind == Some(hir::ConstContext::ConstFn) - && self.tcx.features().staged_api() + && (self.tcx.features().staged_api() + || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked) && is_safe_to_expose_on_stable_const_fn(self.tcx, self.def_id().to_def_id()) } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index cd47c8ece60..264dd364b5b 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -149,6 +149,11 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if let Some(stab) = self.parent_stab { if inherit_deprecation.yes() && stab.is_unstable() { self.index.stab_map.insert(def_id, stab); + if fn_sig.is_some_and(|s| s.header.is_const()) { + let const_stab = + attr::unmarked_crate_const_stab(self.tcx.sess, attrs, stab); + self.index.const_stab_map.insert(def_id, const_stab); + } } } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 5b94f036248..53d5db02ecf 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -391,6 +391,11 @@ #![feature(stdarch_internal)] // tidy-alphabetical-end // +// Library features (crates without staged_api): +// tidy-alphabetical-start +#![feature(rustc_private)] +// tidy-alphabetical-end +// // Only for re-exporting: // tidy-alphabetical-start #![feature(assert_matches)] diff --git a/tests/ui/consts/min_const_fn/auxiliary/unmarked_const_fn_crate.rs b/tests/ui/consts/min_const_fn/auxiliary/unmarked_const_fn_crate.rs new file mode 100644 index 00000000000..aec92c5ae16 --- /dev/null +++ b/tests/ui/consts/min_const_fn/auxiliary/unmarked_const_fn_crate.rs @@ -0,0 +1 @@ +pub const fn just_a_fn() {} diff --git a/tests/ui/consts/min_const_fn/auxiliary/unstable_if_unmarked_const_fn_crate.rs b/tests/ui/consts/min_const_fn/auxiliary/unstable_if_unmarked_const_fn_crate.rs new file mode 100644 index 00000000000..f102902fce3 --- /dev/null +++ b/tests/ui/consts/min_const_fn/auxiliary/unstable_if_unmarked_const_fn_crate.rs @@ -0,0 +1,8 @@ +//@ compile-flags: -Zforce-unstable-if-unmarked + +#![feature(rustc_attrs)] + +pub const fn not_stably_const() {} + +#[rustc_const_stable_indirect] +pub const fn expose_on_stable() {} diff --git a/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.rs b/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.rs new file mode 100644 index 00000000000..f03bfb81a14 --- /dev/null +++ b/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.rs @@ -0,0 +1,23 @@ +//@ aux-build:unstable_if_unmarked_const_fn_crate.rs +//@ aux-build:unmarked_const_fn_crate.rs +#![feature(staged_api, rustc_private)] +#![stable(since="1.0.0", feature = "stable")] + +extern crate unstable_if_unmarked_const_fn_crate; +extern crate unmarked_const_fn_crate; + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "rust1", since = "1.0.0")] +const fn stable_fn() { + // This one is fine. + unstable_if_unmarked_const_fn_crate::expose_on_stable(); + // This one is not. + unstable_if_unmarked_const_fn_crate::not_stably_const(); + //~^ERROR: cannot use `#[feature(rustc_private)]` + unmarked_const_fn_crate::just_a_fn(); + //~^ERROR: cannot be (indirectly) exposed to stable +} + +fn main() { + +} diff --git a/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.stderr b/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.stderr new file mode 100644 index 00000000000..a655c0faab6 --- /dev/null +++ b/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.stderr @@ -0,0 +1,28 @@ +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(rustc_private)]` + --> $DIR/recursive_const_stab_unmarked_crate_imports.rs:15:5 + | +LL | unstable_if_unmarked_const_fn_crate::not_stably_const(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn stable_fn() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(rustc_private)] +LL | const fn stable_fn() { + | + +error: `just_a_fn` cannot be (indirectly) exposed to stable + --> $DIR/recursive_const_stab_unmarked_crate_imports.rs:17:5 + | +LL | unmarked_const_fn_crate::just_a_fn(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.rs b/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.rs new file mode 100644 index 00000000000..51811b14203 --- /dev/null +++ b/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.rs @@ -0,0 +1,24 @@ +//@ compile-flags: -Zforce-unstable-if-unmarked +//@ edition: 2021 +#![feature(const_async_blocks, rustc_attrs, rustc_private)] + +pub const fn not_stably_const() { + // We need to do something const-unstable here. + // For now we use `async`, eventually we might have to add a auxiliary crate + // as a dependency just to be sure we have something const-unstable. + let _x = async { 15 }; +} + +#[rustc_const_stable_indirect] +pub const fn expose_on_stable() { + // Calling `not_stably_const` here is *not* okay. + not_stably_const(); + //~^ERROR: cannot use `#[feature(rustc_private)]` + // Also directly using const-unstable things is not okay. + let _x = async { 15 }; + //~^ERROR: cannot use `#[feature(const_async_blocks)]` +} + +fn main() { + const { expose_on_stable() }; +} diff --git a/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.stderr b/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.stderr new file mode 100644 index 00000000000..d4ba0f9df2d --- /dev/null +++ b/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.stderr @@ -0,0 +1,37 @@ +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(rustc_private)]` + --> $DIR/recursive_const_stab_unstable_if_unmarked.rs:15:5 + | +LL | not_stably_const(); + | ^^^^^^^^^^^^^^^^^^ + | + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | pub const fn expose_on_stable() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(rustc_private)] +LL | pub const fn expose_on_stable() { + | + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_async_blocks)]` + --> $DIR/recursive_const_stab_unstable_if_unmarked.rs:18:14 + | +LL | let _x = async { 15 }; + | ^^^^^^^^^^^^ + | +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | pub const fn expose_on_stable() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(const_async_blocks)] +LL | pub const fn expose_on_stable() { + | + +error: aborting due to 2 previous errors + From e96808162ad7ff5906d7b58d32a25abe139e998c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Nov 2024 21:19:21 +0100 Subject: [PATCH 04/20] ensure that all publicly reachable const fn have const stability info --- compiler/rustc_attr/src/builtin.rs | 50 ++--- .../src/check_consts/check.rs | 24 ++- .../rustc_const_eval/src/check_consts/mod.rs | 13 +- compiler/rustc_expand/src/base.rs | 4 +- compiler/rustc_passes/src/stability.rs | 194 +++++++++--------- src/librustdoc/html/render/mod.rs | 4 +- .../clippy_utils/src/qualify_min_const_fn.rs | 8 +- tests/ui/consts/const-unstable-intrinsic.rs | 6 +- .../ui/consts/const-unstable-intrinsic.stderr | 30 ++- .../rustc-const-stability-require-const.rs | 6 - ...rustc-const-stability-require-const.stderr | 14 +- ...ute-rejects-already-stable-features.stderr | 28 +-- 12 files changed, 177 insertions(+), 204 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 3a7ea36f601..94f9727eb7f 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -16,9 +16,9 @@ use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::UNEXPECTED_CFGS; use rustc_session::parse::feature_err; use rustc_session::{RustcVersion, Session}; +use rustc_span::Span; use rustc_span::hygiene::Transparency; use rustc_span::symbol::{Symbol, kw, sym}; -use rustc_span::{DUMMY_SP, Span}; use crate::fluent_generated; use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause}; @@ -92,9 +92,7 @@ impl Stability { #[derive(HashStable_Generic)] pub struct ConstStability { pub level: StabilityLevel, - /// This can be `None` for functions that do not have an explicit const feature. - /// We still track them for recursive const stability checks. - pub feature: Option, + pub feature: Symbol, /// This is true iff the `const_stable_indirect` attribute is present. pub const_stable_indirect: bool, /// whether the function has a `#[rustc_promotable]` attribute @@ -272,22 +270,19 @@ pub fn find_stability( /// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable` /// attributes in `attrs`. Returns `None` if no stability attributes are found. -/// -/// `is_const_fn` indicates whether this is a function marked as `const`. pub fn find_const_stability( sess: &Session, attrs: &[Attribute], item_sp: Span, - is_const_fn: bool, ) -> Option<(ConstStability, Span)> { let mut const_stab: Option<(ConstStability, Span)> = None; let mut promotable = false; - let mut const_stable_indirect = None; + let mut const_stable_indirect = false; for attr in attrs { match attr.name_or_empty() { sym::rustc_promotable => promotable = true, - sym::rustc_const_stable_indirect => const_stable_indirect = Some(attr.span), + sym::rustc_const_stable_indirect => const_stable_indirect = true, sym::rustc_const_unstable => { if const_stab.is_some() { sess.dcx() @@ -299,7 +294,7 @@ pub fn find_const_stability( const_stab = Some(( ConstStability { level, - feature: Some(feature), + feature, const_stable_indirect: false, promotable: false, }, @@ -317,7 +312,7 @@ pub fn find_const_stability( const_stab = Some(( ConstStability { level, - feature: Some(feature), + feature, const_stable_indirect: false, promotable: false, }, @@ -340,7 +335,7 @@ pub fn find_const_stability( } } } - if const_stable_indirect.is_some() { + if const_stable_indirect { match &mut const_stab { Some((stab, _)) => { if stab.is_const_unstable() { @@ -351,32 +346,13 @@ pub fn find_const_stability( }) } } - _ => {} + _ => { + // This function has no const stability attribute, but has `const_stable_indirect`. + // We ignore that; unmarked functions are subject to recursive const stability + // checks by default so we do carry out the user's intent. + } } } - // Make sure if `const_stable_indirect` is present, that is recorded. Also make sure all `const - // fn` get *some* marker, since we are a staged_api crate and therefore will do recursive const - // stability checks for them. We need to do this because the default for whether an unmarked - // function enforces recursive stability differs between staged-api crates and force-unmarked - // crates: in force-unmarked crates, only functions *explicitly* marked `const_stable_indirect` - // enforce recursive stability. Therefore when `lookup_const_stability` is `None`, we have to - // assume the function does not have recursive stability. All functions that *do* have recursive - // stability must explicitly record this, and so that's what we do for all `const fn` in a - // staged_api crate. - if (is_const_fn || const_stable_indirect.is_some()) && const_stab.is_none() { - let c = ConstStability { - feature: None, - const_stable_indirect: const_stable_indirect.is_some(), - promotable: false, - level: StabilityLevel::Unstable { - reason: UnstableReason::Default, - issue: None, - is_soft: false, - implied_by: None, - }, - }; - const_stab = Some((c, const_stable_indirect.unwrap_or(DUMMY_SP))); - } const_stab } @@ -394,7 +370,7 @@ pub fn unmarked_crate_const_stab( let const_stable_indirect = attrs.iter().any(|a| a.name_or_empty() == sym::rustc_const_stable_indirect); ConstStability { - feature: Some(regular_stab.feature), + feature: regular_stab.feature, const_stable_indirect, promotable: false, level: regular_stab.level, diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 8cd0ecb3e4e..886ebf1a5a8 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -709,6 +709,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // Intrinsics are language primitives, not regular calls, so treat them separately. if let Some(intrinsic) = tcx.intrinsic(callee) { + if !tcx.is_const_fn(callee) { + // Non-const intrinsic. + self.check_op(ops::IntrinsicNonConst { name: intrinsic.name }); + // If we allowed this, we're in miri-unleashed mode, so we might + // as well skip the remaining checks. + return; + } // We use `intrinsic.const_stable` to determine if this can be safely exposed to // stable code, rather than `const_stable_indirect`. This is to make // `#[rustc_const_stable_indirect]` an attribute that is always safe to add. @@ -716,17 +723,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // fallback body is safe to expose on stable. let is_const_stable = intrinsic.const_stable || (!intrinsic.must_be_overridden - && tcx.is_const_fn(callee) && is_safe_to_expose_on_stable_const_fn(tcx, callee)); match tcx.lookup_const_stability(callee) { None => { - // Non-const intrinsic. - self.check_op(ops::IntrinsicNonConst { name: intrinsic.name }); - } - Some(ConstStability { feature: None, .. }) => { - // Intrinsic does not need a separate feature gate (we rely on the - // regular stability checker). However, we have to worry about recursive - // const stability. + // This doesn't need a separate const-stability check -- const-stability equals + // regular stability, and regular stability is checked separately. + // However, we *do* have to worry about *recursive* const stability. if !is_const_stable && self.enforce_recursive_const_stability() { self.dcx().emit_err(errors::UnmarkedIntrinsicExposed { span: self.span, @@ -735,8 +737,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } Some(ConstStability { - feature: Some(feature), level: StabilityLevel::Unstable { .. }, + feature, .. }) => { self.check_op(ops::IntrinsicUnstable { @@ -773,7 +775,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => { // All good. } - None | Some(ConstStability { feature: None, .. }) => { + None => { // This doesn't need a separate const-stability check -- const-stability equals // regular stability, and regular stability is checked separately. // However, we *do* have to worry about *recursive* const stability. @@ -787,8 +789,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } Some(ConstStability { - feature: Some(feature), level: StabilityLevel::Unstable { implied_by: implied_feature, .. }, + feature, .. }) => { // An unstable const fn with a feature gate. diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index 3b2a79793ae..d49d59c2a08 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -110,14 +110,15 @@ pub fn is_safe_to_expose_on_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> b match tcx.lookup_const_stability(def_id) { None => { - // Only marked functions can be trusted. Note that this may be a function in a - // non-staged-API crate where no recursive checks were done! - false + // In a `staged_api` crate, we do enforce recursive const stability for all unmarked + // functions, so we can trust local functions. But in another crate we don't know which + // rules were applied, so we can't trust that. + def_id.is_local() && tcx.features().staged_api() } Some(stab) => { - // We consider things safe-to-expose if they are stable, if they don't have any explicit - // const stability attribute, or if they are marked as `const_stable_indirect`. - stab.is_const_stable() || stab.feature.is_none() || stab.const_stable_indirect + // We consider things safe-to-expose if they are stable or if they are marked as + // `const_stable_indirect`. + stab.is_const_stable() || stab.const_stable_indirect } } } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 7e4bc508e5c..bed500c3032 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -866,9 +866,7 @@ impl SyntaxExtension { }) .unwrap_or_else(|| (None, helper_attrs)); let stability = attr::find_stability(sess, attrs, span); - // We set `is_const_fn` false to avoid getting any implicit const stability. - let const_stability = - attr::find_const_stability(sess, attrs, span, /* is_const_fn */ false); + let const_stability = attr::find_const_stability(sess, attrs, span); let body_stability = attr::find_body_stability(sess, attrs); if let Some((_, sp)) = const_stability { sess.dcx().emit_err(errors::MacroConstStability { diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 264dd364b5b..4a793f1875e 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -16,7 +16,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId}; use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{Constness, FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant}; +use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures}; use rustc_middle::middle::privacy::EffectiveVisibilities; @@ -166,68 +166,11 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { return; } + // # Regular and body stability + let stab = attr::find_stability(self.tcx.sess, attrs, item_sp); - let const_stab = attr::find_const_stability( - self.tcx.sess, - attrs, - item_sp, - fn_sig.is_some_and(|s| s.header.is_const()), - ); let body_stab = attr::find_body_stability(self.tcx.sess, attrs); - // If the current node is a function with const stability attributes (directly given or - // implied), check if the function/method is const or the parent impl block is const. - if let Some(fn_sig) = fn_sig - && !fn_sig.header.is_const() - && const_stab.is_some() - { - self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span }); - } - - // If this is marked const *stable*, it must also be regular-stable. - if let Some((const_stab, const_span)) = const_stab - && let Some(fn_sig) = fn_sig - && const_stab.is_const_stable() - && !stab.is_some_and(|(s, _)| s.is_stable()) - { - self.tcx - .dcx() - .emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span }); - } - - // Stable *language* features shouldn't be used as unstable library features. - // (Not doing this for stable library features is checked by tidy.) - if let Some(( - ConstStability { level: Unstable { .. }, feature: Some(feature), .. }, - const_span, - )) = const_stab - { - if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() { - self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature { - span: const_span, - item_sp, - }); - } - } - - let const_stab = const_stab.map(|(const_stab, _span)| { - self.index.const_stab_map.insert(def_id, const_stab); - const_stab - }); - - // `impl const Trait for Type` items forward their const stability to their - // immediate children. - // FIXME(const_trait_impl): how is this supposed to interact with `#[rustc_const_stable_indirect]`? - // Currently, once that is set, we do not inherit anything from the parent any more. - if const_stab.is_none() { - debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab); - if let Some(parent) = self.parent_const_stab { - if parent.is_const_unstable() { - self.index.const_stab_map.insert(def_id, parent); - } - } - } - if let Some((depr, span)) = &depr && depr.is_since_rustc_version() && stab.is_none() @@ -294,15 +237,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { self.index.implications.insert(implied_by, feature); } - if let Some(ConstStability { - level: Unstable { implied_by: Some(implied_by), .. }, - feature, - .. - }) = const_stab - { - self.index.implications.insert(implied_by, feature.unwrap()); - } - self.index.stab_map.insert(def_id, stab); stab }); @@ -316,6 +250,91 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } + let final_stab = self.index.stab_map.get(&def_id); + + // # Const stability + + let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item_sp); + + // If the current node is a function with const stability attributes (directly given or + // implied), check if the function/method is const. + if let Some(fn_sig) = fn_sig + && !fn_sig.header.is_const() + && const_stab.is_some() + { + self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span }); + } + + // If this is marked const *stable*, it must also be regular-stable. + if let Some((const_stab, const_span)) = const_stab + && let Some(fn_sig) = fn_sig + && const_stab.is_const_stable() + && !stab.is_some_and(|s| s.is_stable()) + { + self.tcx + .dcx() + .emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span }); + } + + // Stable *language* features shouldn't be used as unstable library features. + // (Not doing this for stable library features is checked by tidy.) + if let Some((ConstStability { level: Unstable { .. }, feature, .. }, const_span)) = + const_stab + { + if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() { + self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature { + span: const_span, + item_sp, + }); + } + } + + // After checking the immediate attributes, get rid of the span and compute implied + // const stability: inherit feature gate from regular stability. + let mut const_stab = const_stab.map(|(stab, _span)| stab); + + // If this is a const fn but not annotated with stability markers, see if we can inherit regular stability. + if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() && + // We only ever inherit unstable features. + let Some(inherit_regular_stab) = + final_stab.filter(|s| s.is_unstable()) + { + const_stab = Some(ConstStability { + // We subject these implicitly-const functions to recursive const stability. + const_stable_indirect: true, + promotable: false, + level: inherit_regular_stab.level, + feature: inherit_regular_stab.feature, + }); + } + + // Now that everything is computed, insert it into the table. + const_stab.inspect(|const_stab| { + self.index.const_stab_map.insert(def_id, *const_stab); + }); + + if let Some(ConstStability { + level: Unstable { implied_by: Some(implied_by), .. }, + feature, + .. + }) = const_stab + { + self.index.implications.insert(implied_by, feature); + } + + // `impl const Trait for Type` items forward their const stability to their + // immediate children. + // FIXME(const_trait_impl): how is this supposed to interact with `#[rustc_const_stable_indirect]`? + // Currently, once that is set, we do not inherit anything from the parent any more. + if const_stab.is_none() { + debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab); + if let Some(parent) = self.parent_const_stab { + if parent.is_const_unstable() { + self.index.const_stab_map.insert(def_id, parent); + } + } + } + self.recurse_with_stability_attrs( depr.map(|(d, _)| DeprecationEntry::local(d, def_id)), stab, @@ -570,13 +589,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { } } - fn check_missing_or_wrong_const_stability(&self, def_id: LocalDefId, span: Span) { - // The visitor runs for "unstable-if-unmarked" crates, but we don't yet support - // that on the const side. - if !self.tcx.features().staged_api() { - return; - } - + fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) { // if the const impl is derived using the `derive_const` attribute, // then it would be "stable" at least for the impl. // We gate usages of it using `feature(const_trait_impl)` anyways @@ -587,12 +600,12 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { let is_const = self.tcx.is_const_fn(def_id.to_def_id()) || self.tcx.is_const_trait_impl(def_id.to_def_id()); - let is_stable = - self.tcx.lookup_stability(def_id).is_some_and(|stability| stability.level.is_stable()); - let missing_const_stability_attribute = - self.tcx.lookup_const_stability(def_id).is_none_or(|s| s.feature.is_none()); - if is_const && is_stable && missing_const_stability_attribute { + // Reachable const fn must have a stability attribute. + if is_const + && self.effective_visibilities.is_reachable(def_id) + && self.tcx.lookup_const_stability(def_id).is_none() + { let descr = self.tcx.def_descr(def_id.to_def_id()); self.tcx.dcx().emit_err(errors::MissingConstStabAttr { span, descr }); } @@ -620,7 +633,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } // Ensure stable `const fn` have a const stability attribute. - self.check_missing_or_wrong_const_stability(i.owner_id.def_id, i.span); + self.check_missing_const_stability(i.owner_id.def_id, i.span); intravisit::walk_item(self, i) } @@ -634,7 +647,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { let impl_def_id = self.tcx.hir().get_parent_item(ii.hir_id()); if self.tcx.impl_trait_ref(impl_def_id).is_none() { self.check_missing_stability(ii.owner_id.def_id, ii.span); - self.check_missing_or_wrong_const_stability(ii.owner_id.def_id, ii.span); + self.check_missing_const_stability(ii.owner_id.def_id, ii.span); } intravisit::walk_impl_item(self, ii); } @@ -765,23 +778,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { // For implementations of traits, check the stability of each item // individually as it's possible to have a stable trait with unstable // items. - hir::ItemKind::Impl(hir::Impl { - constness, - of_trait: Some(ref t), - self_ty, - items, - .. - }) => { + hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => { let features = self.tcx.features(); if features.staged_api() { let attrs = self.tcx.hir().attrs(item.hir_id()); let stab = attr::find_stability(self.tcx.sess, attrs, item.span); - let const_stab = attr::find_const_stability( - self.tcx.sess, - attrs, - item.span, - matches!(constness, Constness::Const), - ); + let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item.span); // If this impl block has an #[unstable] attribute, give an // error if all involved types and traits are stable, because diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 8446235fb18..ce96d1d0a95 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1010,9 +1010,7 @@ fn render_stability_since_raw_with_extra( // don't display const unstable if entirely unstable None } else { - let unstable = if let Some(n) = issue - && let Some(feature) = feature - { + let unstable = if let Some(n) = issue { format!( ", def_id: DefId, msrv: &Msrv) -> bool { msrv.meets(const_stab_rust_version) } else { - // Unstable const fn, check if the feature is enabled. We need both the regular stability - // feature and (if set) the const stability feature to const-call this function. - let stab = tcx.lookup_stability(def_id); - let is_enabled = stab.is_some_and(|s| s.is_stable() || tcx.features().enabled(s.feature)) - && const_stab.feature.is_none_or(|f| tcx.features().enabled(f)); - is_enabled && msrv.current().is_none() + // Unstable const fn, check if the feature is enabled. + tcx.features().enabled(const_stab.feature) && msrv.current().is_none() } }) } diff --git a/tests/ui/consts/const-unstable-intrinsic.rs b/tests/ui/consts/const-unstable-intrinsic.rs index 56b552b6a3f..8b38067e46e 100644 --- a/tests/ui/consts/const-unstable-intrinsic.rs +++ b/tests/ui/consts/const-unstable-intrinsic.rs @@ -16,13 +16,13 @@ const fn const_main() { unsafe { unstable_intrinsic::size_of_val(&x); //~^ERROR: unstable library feature `unstable` - //~|ERROR: cannot be (indirectly) exposed to stable + //~|ERROR: not yet stable as a const intrinsic unstable_intrinsic::min_align_of_val(&x); //~^ERROR: unstable library feature `unstable` //~|ERROR: not yet stable as a const intrinsic size_of_val(&x); - //~^ERROR: cannot be (indirectly) exposed to stable + //~^ERROR: cannot use `#[feature(local)]` min_align_of_val(&x); //~^ERROR: cannot use `#[feature(local)]` } @@ -59,6 +59,6 @@ mod fallback { #[rustc_intrinsic] const unsafe fn copy(src: *const T, _dst: *mut T, _count: usize) { super::size_of_val(src); - //~^ ERROR cannot be (indirectly) exposed to stable + //~^ ERROR cannot use `#[feature(local)]` } } diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr index 3e605f3d003..8b61b0904a9 100644 --- a/tests/ui/consts/const-unstable-intrinsic.stderr +++ b/tests/ui/consts/const-unstable-intrinsic.stderr @@ -18,13 +18,13 @@ LL | unstable_intrinsic::min_align_of_val(&x); = help: add `#![feature(unstable)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: intrinsic `unstable_intrinsic::size_of_val` cannot be (indirectly) exposed to stable +error: `size_of_val` is not yet stable as a const intrinsic --> $DIR/const-unstable-intrinsic.rs:17:9 | LL | unstable_intrinsic::size_of_val(&x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval) + = help: add `#![feature(unstable)]` to the crate attributes to enable error: `min_align_of_val` is not yet stable as a const intrinsic --> $DIR/const-unstable-intrinsic.rs:20:9 @@ -34,13 +34,22 @@ LL | unstable_intrinsic::min_align_of_val(&x); | = help: add `#![feature(unstable)]` to the crate attributes to enable -error: intrinsic `size_of_val` cannot be (indirectly) exposed to stable +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]` --> $DIR/const-unstable-intrinsic.rs:24:9 | LL | size_of_val(&x); | ^^^^^^^^^^^^^^^ | - = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval) +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn const_main() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(local)] +LL | const fn const_main() { + | error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]` --> $DIR/const-unstable-intrinsic.rs:26:9 @@ -67,13 +76,22 @@ LL | unsafe { copy(src, dst, count) } | = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval) -error: intrinsic `size_of_val` cannot be (indirectly) exposed to stable +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]` --> $DIR/const-unstable-intrinsic.rs:61:9 | LL | super::size_of_val(src); | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval) +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const unsafe fn copy(src: *const T, _dst: *mut T, _count: usize) { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(local)] +LL | const unsafe fn copy(src: *const T, _dst: *mut T, _count: usize) { + | error: aborting due to 8 previous errors diff --git a/tests/ui/consts/rustc-const-stability-require-const.rs b/tests/ui/consts/rustc-const-stability-require-const.rs index 6cc3f0f0da1..ad27fcf6cb9 100644 --- a/tests/ui/consts/rustc-const-stability-require-const.rs +++ b/tests/ui/consts/rustc-const-stability-require-const.rs @@ -56,9 +56,3 @@ const fn barfoo_unmarked() {} #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")] pub const fn barfoo_unstable() {} //~^ ERROR can only be applied to functions that are declared `#[stable]` - -// `#[rustc_const_stable_indirect]` also requires a const fn -#[rustc_const_stable_indirect] -#[unstable(feature = "unstable", issue = "none")] -pub fn not_a_const_fn() {} -//~^ ERROR require the function or method to be `const` diff --git a/tests/ui/consts/rustc-const-stability-require-const.stderr b/tests/ui/consts/rustc-const-stability-require-const.stderr index d9a7d37cbcd..4b13826584d 100644 --- a/tests/ui/consts/rustc-const-stability-require-const.stderr +++ b/tests/ui/consts/rustc-const-stability-require-const.stderr @@ -86,17 +86,5 @@ LL | #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")] LL | pub const fn barfoo_unstable() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` - --> $DIR/rustc-const-stability-require-const.rs:63:1 - | -LL | pub fn not_a_const_fn() {} - | ^^^^^^^^^^^^^^^^^^^^^^^ - | -help: make the function or method const - --> $DIR/rustc-const-stability-require-const.rs:63:1 - | -LL | pub fn not_a_const_fn() {} - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 9 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr index d599523c727..319056a9c88 100644 --- a/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr +++ b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr @@ -1,17 +1,3 @@ -error: can't mark as unstable using an already stable feature - --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 - | -LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable -LL | const fn my_fun() {} - | -------------------- the stability attribute annotates this item - | -help: consider removing the attribute - --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 - | -LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: can't mark as unstable using an already stable feature --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1 | @@ -27,5 +13,19 @@ help: consider removing the attribute LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: can't mark as unstable using an already stable feature + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 + | +LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable +LL | const fn my_fun() {} + | -------------------- the stability attribute annotates this item + | +help: consider removing the attribute + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 + | +LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: aborting due to 2 previous errors From baa95efa7a8045d7174bf5aa57508d4ac82899f8 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 16 Oct 2024 19:42:25 +0300 Subject: [PATCH 05/20] use allowed "if-unchanged" logic for compiler builds Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 82 ++++++++++++++++++++----- 1 file changed, 65 insertions(+), 17 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index f977c285a74..bb1c7219eda 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -28,6 +28,53 @@ use crate::utils::cache::{INTERNER, Interned}; use crate::utils::channel::{self, GitInfo}; use crate::utils::helpers::{self, exe, output, t}; +/// Each path in this list is considered "allowed" in the `download-rustc="if-unchanged"` logic. +/// This means they can be modified and changes to these paths should never trigger a compiler build +/// when "if-unchanged" is set. +/// +/// NOTE: Paths must have the ":!" prefix to tell git to ignore changes in those paths during +/// the diff check. +/// +/// WARNING: Be cautious when adding paths to this list. If a path that influences the compiler build +/// is added here, it will cause bootstrap to skip necessary rebuilds, which may lead to risky results. +const RUSTC_IF_UNCHANGED_ALLOWED_PATHS: &[&str] = &[ + ":!.clang-format", + ":!.editorconfig", + ":!.git-blame-ignore-revs", + ":!.gitattributes", + ":!.gitignore", + ":!.gitmodules", + ":!.ignore", + ":!.mailmap", + ":!CODE_OF_CONDUCT.md", + ":!CONTRIBUTING.md", + ":!COPYRIGHT", + ":!INSTALL.md", + ":!LICENSE-APACHE", + ":!LICENSE-MIT", + ":!LICENSES", + ":!README.md", + ":!RELEASES.md", + ":!REUSE.toml", + ":!config.example.toml", + ":!configure", + ":!rust-bors.toml", + ":!rustfmt.toml", + ":!tests", + ":!triagebot.toml", + ":!x", + ":!x.ps1", + ":!x.py", + ":!src/ci/cpu-usage-over-time.py", + ":!src/ci/publish_toolstate.sh", + ":!src/doc", + ":!src/etc", + ":!src/librustdoc", + ":!src/rustdoc-json-types", + ":!src/tools", + ":!src/README.md", +]; + macro_rules! check_ci_llvm { ($name:expr) => { assert!( @@ -2768,32 +2815,33 @@ impl Config { } }; - let mut files_to_track = vec!["compiler", "src/version", "src/stage0", "src/ci/channel"]; + // RUSTC_IF_UNCHANGED_ALLOWED_PATHS + let mut allowed_paths = RUSTC_IF_UNCHANGED_ALLOWED_PATHS.to_vec(); - // In CI, disable ci-rustc if there are changes in the library tree. But for non-CI, ignore + // In CI, disable ci-rustc if there are changes in the library tree. But for non-CI, allow // these changes to speed up the build process for library developers. This provides consistent // functionality for library developers between `download-rustc=true` and `download-rustc="if-unchanged"` // options. - if CiEnv::is_ci() { - files_to_track.push("library"); + if !CiEnv::is_ci() { + allowed_paths.push(":!library"); } // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. - let commit = - match self.last_modified_commit(&files_to_track, "download-rustc", if_unchanged) { - Some(commit) => commit, - None => { - if if_unchanged { - return None; - } - println!("ERROR: could not find commit hash for downloading rustc"); - println!("HELP: maybe your repository history is too shallow?"); - println!("HELP: consider disabling `download-rustc`"); - println!("HELP: or fetch enough history to include one upstream commit"); - crate::exit!(1); + let commit = match self.last_modified_commit(&allowed_paths, "download-rustc", if_unchanged) + { + Some(commit) => commit, + None => { + if if_unchanged { + return None; } - }; + println!("ERROR: could not find commit hash for downloading rustc"); + println!("HELP: maybe your repository history is too shallow?"); + println!("HELP: consider setting `rust.download-rustc=false` in config.toml"); + println!("HELP: or fetch enough history to include one upstream commit"); + crate::exit!(1); + } + }; if CiEnv::is_ci() && { let head_sha = From 72e63e3ad58347ffe8a5e00e47738c1fd6295fa2 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 17 Oct 2024 15:15:34 +0300 Subject: [PATCH 06/20] add test coverage for `RUSTC_IF_UNCHANGED_ALLOWED_PATHS` Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 2 +- src/bootstrap/src/core/config/tests.rs | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index bb1c7219eda..b4bea7a68de 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -37,7 +37,7 @@ use crate::utils::helpers::{self, exe, output, t}; /// /// WARNING: Be cautious when adding paths to this list. If a path that influences the compiler build /// is added here, it will cause bootstrap to skip necessary rebuilds, which may lead to risky results. -const RUSTC_IF_UNCHANGED_ALLOWED_PATHS: &[&str] = &[ +pub(crate) const RUSTC_IF_UNCHANGED_ALLOWED_PATHS: &[&str] = &[ ":!.clang-format", ":!.editorconfig", ":!.git-blame-ignore-revs", diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index 1f02757682c..7e4eca3c5b0 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -8,7 +8,7 @@ use clap::CommandFactory; use serde::Deserialize; use super::flags::Flags; -use super::{ChangeIdWrapper, Config}; +use super::{ChangeIdWrapper, Config, RUSTC_IF_UNCHANGED_ALLOWED_PATHS}; use crate::core::build_steps::clippy::get_clippy_rules_in_order; use crate::core::build_steps::llvm; use crate::core::config::{LldMode, Target, TargetSelection, TomlConfig}; @@ -410,3 +410,18 @@ fn jobs_precedence() { ); assert_eq!(config.jobs, Some(123)); } + +#[test] +fn check_rustc_if_unchanged_paths() { + let config = parse(""); + let normalised_allowed_paths: Vec<_> = RUSTC_IF_UNCHANGED_ALLOWED_PATHS + .iter() + .map(|t| { + t.strip_prefix(":!").expect(&format!("{t} doesn't have ':!' prefix, but it should.")) + }) + .collect(); + + for p in normalised_allowed_paths { + assert!(config.src.join(p).exists(), "{p} doesn't exist."); + } +} From a00fd7a965c455d137c887ebbb7ed580719f080c Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sun, 10 Nov 2024 23:14:39 +0300 Subject: [PATCH 07/20] warn about "src/bootstrap" on `RUSTC_IF_UNCHANGED_ALLOWED_PATHS` Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index b4bea7a68de..adfd7c42f23 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -37,6 +37,8 @@ use crate::utils::helpers::{self, exe, output, t}; /// /// WARNING: Be cautious when adding paths to this list. If a path that influences the compiler build /// is added here, it will cause bootstrap to skip necessary rebuilds, which may lead to risky results. +/// For example, "src/bootstrap" should never be included in this list as it plays a crucial role in the +/// final output/compiler, which can be significantly affected by changes made to the bootstrap sources. pub(crate) const RUSTC_IF_UNCHANGED_ALLOWED_PATHS: &[&str] = &[ ":!.clang-format", ":!.editorconfig", From 405017ac354c4d07300204abc7b7035b1776c9c1 Mon Sep 17 00:00:00 2001 From: Henry Jiang Date: Sun, 10 Nov 2024 21:52:18 -0500 Subject: [PATCH 08/20] refactor flags --- .../src/external_deps/rustc.rs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index c2989aedee1..494daeca963 100644 --- a/src/tools/run-make-support/src/external_deps/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -346,7 +346,7 @@ impl Rustc { // endif // endif // ``` - let flag = if is_windows() { + if is_windows() { // So this is a bit hacky: we can't use the DLL version of libstdc++ because // it pulls in the DLL version of libgcc, which means that we end up with 2 // instances of the DW2 unwinding implementation. This is a problem on @@ -362,21 +362,19 @@ impl Rustc { // So we end up with the following hack: we link use static:-bundle to only // link the parts of libstdc++ that we actually use, which doesn't include // the dependency on the pthreads DLL. - if is_msvc() { None } else { Some("-lstatic:-bundle=stdc++") } + if !is_msvc() { + self.cmd.arg("-lstatic:-bundle=stdc++"); + }; } else if is_darwin() { - Some("-lc++") + self.cmd.arg("-lc++"); } else if is_aix() { self.cmd.arg("-lc++"); - Some("-lc++abi") + self.cmd.arg("-lc++abi"); } else { - match &uname()[..] { - "FreeBSD" | "SunOS" | "OpenBSD" => None, - _ => Some("-lstdc++"), - } + if !matches!(&uname()[..], "FreeBSD" | "SunOS" | "OpenBSD") { + self.cmd.arg("-lstdc++"); + }; }; - if let Some(flag) = flag { - self.cmd.arg(flag); - } self } } From 6b38a159e5d1c3c154c24ff38786e40b71dd4710 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sun, 10 Nov 2024 23:36:44 +0300 Subject: [PATCH 09/20] reduce `RUSTC_IF_UNCHANGED_ALLOWED_PATHS` significantly Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 35 ++----------------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index adfd7c42f23..8afabda1403 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -39,42 +39,11 @@ use crate::utils::helpers::{self, exe, output, t}; /// is added here, it will cause bootstrap to skip necessary rebuilds, which may lead to risky results. /// For example, "src/bootstrap" should never be included in this list as it plays a crucial role in the /// final output/compiler, which can be significantly affected by changes made to the bootstrap sources. +#[rustfmt::skip] // We don't want rustfmt to oneline this list pub(crate) const RUSTC_IF_UNCHANGED_ALLOWED_PATHS: &[&str] = &[ - ":!.clang-format", - ":!.editorconfig", - ":!.git-blame-ignore-revs", - ":!.gitattributes", - ":!.gitignore", - ":!.gitmodules", - ":!.ignore", - ":!.mailmap", - ":!CODE_OF_CONDUCT.md", - ":!CONTRIBUTING.md", - ":!COPYRIGHT", - ":!INSTALL.md", - ":!LICENSE-APACHE", - ":!LICENSE-MIT", - ":!LICENSES", - ":!README.md", - ":!RELEASES.md", - ":!REUSE.toml", - ":!config.example.toml", - ":!configure", - ":!rust-bors.toml", - ":!rustfmt.toml", + ":!src/tools", ":!tests", ":!triagebot.toml", - ":!x", - ":!x.ps1", - ":!x.py", - ":!src/ci/cpu-usage-over-time.py", - ":!src/ci/publish_toolstate.sh", - ":!src/doc", - ":!src/etc", - ":!src/librustdoc", - ":!src/rustdoc-json-types", - ":!src/tools", - ":!src/README.md", ]; macro_rules! check_ci_llvm { From bc7531089efdbb868711ccd66dd83f2b18cb560c Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sun, 10 Nov 2024 23:52:56 +0300 Subject: [PATCH 10/20] move `src/tools/build_helper` into `src/build_helper` Signed-off-by: onur-ozkan --- Cargo.toml | 2 +- src/bootstrap/Cargo.toml | 2 +- src/bootstrap/src/core/build_steps/clippy.rs | 2 +- src/bootstrap/src/core/build_steps/doc.rs | 2 +- src/bootstrap/src/core/build_steps/test.rs | 4 ++-- src/{tools => }/build_helper/Cargo.toml | 0 src/{tools => }/build_helper/README.md | 0 src/{tools => }/build_helper/src/ci.rs | 0 src/{tools => }/build_helper/src/drop_bomb/mod.rs | 0 src/{tools => }/build_helper/src/drop_bomb/tests.rs | 0 src/{tools => }/build_helper/src/git.rs | 0 src/{tools => }/build_helper/src/lib.rs | 0 src/{tools => }/build_helper/src/metrics.rs | 0 src/{tools => }/build_helper/src/stage0_parser.rs | 2 +- src/{tools => }/build_helper/src/util.rs | 0 src/tools/bump-stage0/Cargo.toml | 2 +- src/tools/compiletest/Cargo.toml | 2 +- src/tools/opt-dist/Cargo.toml | 2 +- src/tools/run-make-support/Cargo.toml | 2 +- src/tools/rustdoc-gui-test/Cargo.toml | 2 +- src/tools/suggest-tests/Cargo.toml | 2 +- src/tools/tidy/Cargo.toml | 2 +- 22 files changed, 14 insertions(+), 14 deletions(-) rename src/{tools => }/build_helper/Cargo.toml (100%) rename src/{tools => }/build_helper/README.md (100%) rename src/{tools => }/build_helper/src/ci.rs (100%) rename src/{tools => }/build_helper/src/drop_bomb/mod.rs (100%) rename src/{tools => }/build_helper/src/drop_bomb/tests.rs (100%) rename src/{tools => }/build_helper/src/git.rs (100%) rename src/{tools => }/build_helper/src/lib.rs (100%) rename src/{tools => }/build_helper/src/metrics.rs (100%) rename src/{tools => }/build_helper/src/stage0_parser.rs (97%) rename src/{tools => }/build_helper/src/util.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index e1d667bf015..b773030b4ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,12 +2,12 @@ resolver = "2" members = [ "compiler/rustc", + "src/build_helper", "src/etc/test-float-parse", "src/rustc-std-workspace/rustc-std-workspace-core", "src/rustc-std-workspace/rustc-std-workspace-alloc", "src/rustc-std-workspace/rustc-std-workspace-std", "src/rustdoc-json-types", - "src/tools/build_helper", "src/tools/cargotest", "src/tools/clippy", "src/tools/clippy/clippy_dev", diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index ba505089a00..7950f1004a2 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -40,7 +40,7 @@ test = false cc = "=1.1.22" cmake = "=0.1.48" -build_helper = { path = "../tools/build_helper" } +build_helper = { path = "../build_helper" } clap = { version = "4.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] } clap_complete = "4.4" fd-lock = "4.0" diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index cd198c425c0..fb030b9b781 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -295,7 +295,7 @@ macro_rules! lint_any { lint_any!( Bootstrap, "src/bootstrap", "bootstrap"; - BuildHelper, "src/tools/build_helper", "build_helper"; + BuildHelper, "src/build_helper", "build_helper"; BuildManifest, "src/tools/build-manifest", "build-manifest"; CargoMiri, "src/tools/miri/cargo-miri", "cargo-miri"; Clippy, "src/tools/clippy", "clippy"; diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 69ec832a44a..8a9321f8e79 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -1030,7 +1030,7 @@ macro_rules! tool_doc { // NOTE: make sure to register these in `Builder::get_step_description`. tool_doc!( BuildHelper, - "src/tools/build_helper", + "src/build_helper", rustc_tool = false, is_library = true, crates = ["build_helper"] diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 2c36d8bab82..532c8f767eb 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1354,7 +1354,7 @@ impl Step for CrateBuildHelper { const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/tools/build_helper") + run.path("src/build_helper") } fn make_run(run: RunConfig<'_>) { @@ -1372,7 +1372,7 @@ impl Step for CrateBuildHelper { Mode::ToolBootstrap, host, Kind::Test, - "src/tools/build_helper", + "src/build_helper", SourceType::InTree, &[], ); diff --git a/src/tools/build_helper/Cargo.toml b/src/build_helper/Cargo.toml similarity index 100% rename from src/tools/build_helper/Cargo.toml rename to src/build_helper/Cargo.toml diff --git a/src/tools/build_helper/README.md b/src/build_helper/README.md similarity index 100% rename from src/tools/build_helper/README.md rename to src/build_helper/README.md diff --git a/src/tools/build_helper/src/ci.rs b/src/build_helper/src/ci.rs similarity index 100% rename from src/tools/build_helper/src/ci.rs rename to src/build_helper/src/ci.rs diff --git a/src/tools/build_helper/src/drop_bomb/mod.rs b/src/build_helper/src/drop_bomb/mod.rs similarity index 100% rename from src/tools/build_helper/src/drop_bomb/mod.rs rename to src/build_helper/src/drop_bomb/mod.rs diff --git a/src/tools/build_helper/src/drop_bomb/tests.rs b/src/build_helper/src/drop_bomb/tests.rs similarity index 100% rename from src/tools/build_helper/src/drop_bomb/tests.rs rename to src/build_helper/src/drop_bomb/tests.rs diff --git a/src/tools/build_helper/src/git.rs b/src/build_helper/src/git.rs similarity index 100% rename from src/tools/build_helper/src/git.rs rename to src/build_helper/src/git.rs diff --git a/src/tools/build_helper/src/lib.rs b/src/build_helper/src/lib.rs similarity index 100% rename from src/tools/build_helper/src/lib.rs rename to src/build_helper/src/lib.rs diff --git a/src/tools/build_helper/src/metrics.rs b/src/build_helper/src/metrics.rs similarity index 100% rename from src/tools/build_helper/src/metrics.rs rename to src/build_helper/src/metrics.rs diff --git a/src/tools/build_helper/src/stage0_parser.rs b/src/build_helper/src/stage0_parser.rs similarity index 97% rename from src/tools/build_helper/src/stage0_parser.rs rename to src/build_helper/src/stage0_parser.rs index ff05b116989..2a0c12a1c91 100644 --- a/src/tools/build_helper/src/stage0_parser.rs +++ b/src/build_helper/src/stage0_parser.rs @@ -25,7 +25,7 @@ pub struct Stage0Config { } pub fn parse_stage0_file() -> Stage0 { - let stage0_content = include_str!("../../../stage0"); + let stage0_content = include_str!("../../stage0"); let mut stage0 = Stage0::default(); for line in stage0_content.lines() { diff --git a/src/tools/build_helper/src/util.rs b/src/build_helper/src/util.rs similarity index 100% rename from src/tools/build_helper/src/util.rs rename to src/build_helper/src/util.rs diff --git a/src/tools/bump-stage0/Cargo.toml b/src/tools/bump-stage0/Cargo.toml index de5d821133d..6ee7a831839 100644 --- a/src/tools/bump-stage0/Cargo.toml +++ b/src/tools/bump-stage0/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] anyhow = "1.0.34" -build_helper = { path = "../build_helper" } +build_helper = { path = "../../build_helper" } curl = "0.4.38" indexmap = { version = "2.0.0", features = ["serde"] } serde = { version = "1.0.125", features = ["derive"] } diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index cef6b525a7b..b784bdb7139 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -14,7 +14,7 @@ unified-diff = "0.2.1" getopts = "0.2" indexmap = "2.0.0" miropt-test-tools = { path = "../miropt-test-tools" } -build_helper = { path = "../build_helper" } +build_helper = { path = "../../build_helper" } tracing = "0.1" tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } regex = "1.0" diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml index d34f8ad0520..d0413911014 100644 --- a/src/tools/opt-dist/Cargo.toml +++ b/src/tools/opt-dist/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -build_helper = { path = "../build_helper" } +build_helper = { path = "../../build_helper" } env_logger = "0.11" log = "0.4" anyhow = { version = "1", features = ["backtrace"] } diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 3affa199fa5..3c172b2d956 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -10,7 +10,7 @@ similar = "2.5.0" wasmparser = { version = "0.216", default-features = false, features = ["std"] } regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace gimli = "0.31.0" -build_helper = { path = "../build_helper" } +build_helper = { path = "../../build_helper" } serde_json = "1.0" libc = "0.2" diff --git a/src/tools/rustdoc-gui-test/Cargo.toml b/src/tools/rustdoc-gui-test/Cargo.toml index 4cb200ebc7c..f7384a98f85 100644 --- a/src/tools/rustdoc-gui-test/Cargo.toml +++ b/src/tools/rustdoc-gui-test/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -build_helper = { path = "../build_helper" } +build_helper = { path = "../../build_helper" } compiletest = { path = "../compiletest" } getopts = "0.2" walkdir = "2" diff --git a/src/tools/suggest-tests/Cargo.toml b/src/tools/suggest-tests/Cargo.toml index 7c048d53a50..d6f86078d7e 100644 --- a/src/tools/suggest-tests/Cargo.toml +++ b/src/tools/suggest-tests/Cargo.toml @@ -5,4 +5,4 @@ edition = "2021" [dependencies] glob = "0.3.0" -build_helper = { version = "0.1.0", path = "../build_helper" } +build_helper = { version = "0.1.0", path = "../../build_helper" } diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index 42e608ff5ce..bc75787fb1a 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" autobins = false [dependencies] -build_helper = { path = "../build_helper" } +build_helper = { path = "../../build_helper" } cargo_metadata = "0.18" regex = "1" miropt-test-tools = { path = "../miropt-test-tools" } From 4dfc05237f7230c349a64d6f5b1ede3a0ed865c1 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sun, 10 Nov 2024 23:37:14 +0300 Subject: [PATCH 11/20] Revert "do not trust download-rustc=if-unchanged on CI for now" This reverts commit b3c212103b826cde383093fab2f4237bb5736923. --- src/ci/run.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ci/run.sh b/src/ci/run.sh index 9f39ad9c55c..8e2f525db68 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -179,9 +179,7 @@ else fi if [ "$NO_DOWNLOAD_CI_RUSTC" = "" ]; then - # disabled for now, see https://github.com/rust-lang/rust/issues/131658 - #RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.download-rustc=if-unchanged" - true + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.download-rustc=if-unchanged" fi fi From 2d143ab30c03492be7c34e4665488fa95ef9701e Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 11 Nov 2024 11:27:53 +0300 Subject: [PATCH 12/20] update "if-unchanged" comments in config.example.toml Signed-off-by: onur-ozkan --- config.example.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/config.example.toml b/config.example.toml index cd7ec6a05bc..62c41fee31b 100644 --- a/config.example.toml +++ b/config.example.toml @@ -500,8 +500,9 @@ # This is useful if you are working on tools, doc-comments, or library (you will be able to build # the standard library without needing to build the compiler). # -# Set this to "if-unchanged" to only download if the compiler (and library if running on CI) have -# not been modified. +# Set this to "if-unchanged" if you are working on `src/tools`, `tests` or `library` (on CI, `library` +# changes triggers in-tree compiler build) to speed up the build process. +# # Set this to `true` to download unconditionally. #download-rustc = false From 5b7423c2fc9a4c6f21008baff583c0d9e42f3b58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 12 Nov 2024 00:33:23 +0100 Subject: [PATCH 13/20] Triagebot: Consolidate the T-compiler ad hoc groups --- triagebot.toml | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 4eb80f2058d..80349596555 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -978,30 +978,24 @@ users_on_vacation = [ ] [assign.adhoc_groups] -compiler-team = [ - "@cjgillot", - "@compiler-errors", - "@petrochenkov", - "@davidtwco", - "@estebank", - "@lcnr", - "@oli-obk", - "@pnkfelix", - "@wesleywiser", -] -compiler-team-contributors = [ - "@TaKO8Ki", - "@Nadrieril", - "@nnethercote", - "@fmease", - "@fee1-dead", - "@jieyouxu", +compiler = [ "@BoxyUwU", "@chenyukang", -] -compiler = [ - "compiler-team", - "compiler-team-contributors", + "@cjgillot", + "@compiler-errors", + "@davidtwco", + "@estebank", + "@fee1-dead", + "@fmease", + "@jieyouxu", + "@lcnr", + "@Nadrieril", + "@nnethercote", + "@oli-obk", + "@petrochenkov", + "@pnkfelix", + "@TaKO8Ki", + "@wesleywiser", ] libs = [ "@cuviper", From 0dc6c1e59421e44e15cda1cef307b0381ba12468 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 12 Nov 2024 02:54:42 +0000 Subject: [PATCH 14/20] Make precise capturing suggestion machine-applicable only if it has not APITs --- compiler/rustc_trait_selection/src/errors.rs | 10 ++++++- ...overcaptures-2024-machine-applicable.fixed | 13 ++++++++++ .../overcaptures-2024-machine-applicable.rs | 13 ++++++++++ ...vercaptures-2024-machine-applicable.stderr | 26 +++++++++++++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 tests/ui/impl-trait/precise-capturing/overcaptures-2024-machine-applicable.fixed create mode 100644 tests/ui/impl-trait/precise-capturing/overcaptures-2024-machine-applicable.rs create mode 100644 tests/ui/impl-trait/precise-capturing/overcaptures-2024-machine-applicable.stderr diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 3e06d0807d8..afac6fc6004 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1907,10 +1907,18 @@ impl Subdiagnostic for AddPreciseCapturingForOvercapture { diag: &mut Diag<'_, G>, _f: &F, ) { + let applicability = if self.apit_spans.is_empty() { + Applicability::MachineApplicable + } else { + // If there are APIT that are converted to regular parameters, + // then this may make the API turbofishable in ways that were + // not intended. + Applicability::MaybeIncorrect + }; diag.multipart_suggestion_verbose( fluent::trait_selection_precise_capturing_overcaptures, self.suggs, - Applicability::MaybeIncorrect, + applicability, ); if !self.apit_spans.is_empty() { diag.span_note( diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024-machine-applicable.fixed b/tests/ui/impl-trait/precise-capturing/overcaptures-2024-machine-applicable.fixed new file mode 100644 index 00000000000..960f2f1bb13 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024-machine-applicable.fixed @@ -0,0 +1,13 @@ +//@ run-rustfix +//@ rustfix-only-machine-applicable + +// Make sure that simple overcapture suggestions remain machine applicable. + +#![allow(unused)] +#![deny(impl_trait_overcaptures)] + +fn named<'a>(x: &'a i32) -> impl Sized + use<> { *x } +//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 +//~| WARN this changes meaning in Rust 2024 + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024-machine-applicable.rs b/tests/ui/impl-trait/precise-capturing/overcaptures-2024-machine-applicable.rs new file mode 100644 index 00000000000..dc9efbf3b95 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024-machine-applicable.rs @@ -0,0 +1,13 @@ +//@ run-rustfix +//@ rustfix-only-machine-applicable + +// Make sure that simple overcapture suggestions remain machine applicable. + +#![allow(unused)] +#![deny(impl_trait_overcaptures)] + +fn named<'a>(x: &'a i32) -> impl Sized { *x } +//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 +//~| WARN this changes meaning in Rust 2024 + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024-machine-applicable.stderr b/tests/ui/impl-trait/precise-capturing/overcaptures-2024-machine-applicable.stderr new file mode 100644 index 00000000000..35fff9ef170 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024-machine-applicable.stderr @@ -0,0 +1,26 @@ +error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 + --> $DIR/overcaptures-2024-machine-applicable.rs:9:29 + | +LL | fn named<'a>(x: &'a i32) -> impl Sized { *x } + | ^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +note: specifically, this lifetime is in scope but not mentioned in the type's bounds + --> $DIR/overcaptures-2024-machine-applicable.rs:9:10 + | +LL | fn named<'a>(x: &'a i32) -> impl Sized { *x } + | ^^ + = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 +note: the lint level is defined here + --> $DIR/overcaptures-2024-machine-applicable.rs:7:9 + | +LL | #![deny(impl_trait_overcaptures)] + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: use the precise capturing `use<...>` syntax to make the captures explicit + | +LL | fn named<'a>(x: &'a i32) -> impl Sized + use<> { *x } + | +++++++ + +error: aborting due to 1 previous error + From 378049633dfad641f5c9ed0cea085a9c9d0ae56e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Nov 2024 07:43:03 +0100 Subject: [PATCH 15/20] allow rustc_private feature in force-unstable-if-unmarked crates --- .../src/check_consts/check.rs | 21 +++++++++++++++++-- .../rustc_const_eval/src/check_consts/mod.rs | 2 +- library/std/src/lib.rs | 5 ----- ...rsive_const_stab_unmarked_crate_imports.rs | 8 +++---- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 886ebf1a5a8..c3efca28c68 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -3,6 +3,7 @@ use std::assert_matches::assert_matches; use std::borrow::Cow; use std::mem; +use std::num::NonZero; use std::ops::Deref; use rustc_attr::{ConstStability, StabilityLevel}; @@ -789,7 +790,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } Some(ConstStability { - level: StabilityLevel::Unstable { implied_by: implied_feature, .. }, + level: StabilityLevel::Unstable { implied_by: implied_feature, issue, .. }, feature, .. }) => { @@ -812,7 +813,23 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // to allow this. let feature_enabled = callee.is_local() || tcx.features().enabled(feature) - || implied_feature.is_some_and(|f| tcx.features().enabled(f)); + || implied_feature.is_some_and(|f| tcx.features().enabled(f)) + || { + // When we're compiling the compiler itself we may pull in + // crates from crates.io, but those crates may depend on other + // crates also pulled in from crates.io. We want to ideally be + // able to compile everything without requiring upstream + // modifications, so in the case that this looks like a + // `rustc_private` crate (e.g., a compiler crate) and we also have + // the `-Z force-unstable-if-unmarked` flag present (we're + // compiling a compiler crate), then let this missing feature + // annotation slide. + // This matches what we do in `eval_stability_allow_unstable` for + // regular stability. + feature == sym::rustc_private + && issue == NonZero::new(27812) + && self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked + }; // We do *not* honor this if we are in the "danger zone": we have to enforce // recursive const-stability and the callee is not safe-to-expose. In that // case we need `check_op` to do the check. diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index d49d59c2a08..ebdd55a4f70 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -53,7 +53,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> { } pub fn enforce_recursive_const_stability(&self) -> bool { - // We can skip this if neither `staged_api` nor `-Zforrce-unstable-if-unmarked` are enabled, + // We can skip this if neither `staged_api` nor `-Zforce-unstable-if-unmarked` are enabled, // since in such crates `lookup_const_stability` will always be `None`. self.const_kind == Some(hir::ConstContext::ConstFn) && (self.tcx.features().staged_api() diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 53d5db02ecf..5b94f036248 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -391,11 +391,6 @@ #![feature(stdarch_internal)] // tidy-alphabetical-end // -// Library features (crates without staged_api): -// tidy-alphabetical-start -#![feature(rustc_private)] -// tidy-alphabetical-end -// // Only for re-exporting: // tidy-alphabetical-start #![feature(assert_matches)] diff --git a/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.rs b/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.rs index f03bfb81a14..06ce406fd89 100644 --- a/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.rs +++ b/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.rs @@ -1,10 +1,10 @@ //@ aux-build:unstable_if_unmarked_const_fn_crate.rs //@ aux-build:unmarked_const_fn_crate.rs #![feature(staged_api, rustc_private)] -#![stable(since="1.0.0", feature = "stable")] +#![stable(since = "1.0.0", feature = "stable")] -extern crate unstable_if_unmarked_const_fn_crate; extern crate unmarked_const_fn_crate; +extern crate unstable_if_unmarked_const_fn_crate; #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] @@ -18,6 +18,4 @@ const fn stable_fn() { //~^ERROR: cannot be (indirectly) exposed to stable } -fn main() { - -} +fn main() {} From c6659251c92c13c958c1b086f804abf1ec8e247f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Tue, 12 Nov 2024 11:21:43 +0000 Subject: [PATCH 16/20] clarify `must_produce_diag` ICE for debugging --- compiler/rustc_errors/src/lib.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 94365a89adc..98200c367f9 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -623,12 +623,25 @@ impl Drop for DiagCtxtInner { self.flush_delayed() } + // Sanity check: did we use some of the expensive `trimmed_def_paths` functions + // unexpectedly, that is, without producing diagnostics? If so, for debugging purposes, we + // suggest where this happened and how to avoid it. if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() { if let Some(backtrace) = &self.must_produce_diag { + let suggestion = match backtrace.status() { + BacktraceStatus::Disabled => String::from( + "Backtraces are currently disabled: set `RUST_BACKTRACE=1` and re-run \ + to see where it happened.", + ), + BacktraceStatus::Captured => format!( + "This happened in the following `must_produce_diag` call's backtrace:\n\ + {backtrace}", + ), + _ => String::from("(impossible to capture backtrace where this happened)"), + }; panic!( - "must_produce_diag: `trimmed_def_paths` called but no diagnostics emitted; \ - `with_no_trimmed_paths` for debugging. \ - called at: {backtrace}" + "`trimmed_def_paths` called, diagnostics were expected but none were emitted. \ + Use `with_no_trimmed_paths` for debugging. {suggestion}" ); } } From 2a9cc8f4d6aee54ecf1882bfaa690165b52d66f2 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 11 Nov 2024 15:32:25 +0000 Subject: [PATCH 17/20] Declare all MIR passes in a list --- compiler/rustc_mir_transform/src/lib.rs | 204 ++++++++++++------ .../rustc_mir_transform/src/pass_manager.rs | 12 +- 2 files changed, 154 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index e18f66ac0a3..66ac3d30ca4 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -40,77 +40,159 @@ use tracing::{debug, trace}; #[macro_use] mod pass_manager; +use std::sync::LazyLock; + use pass_manager::{self as pm, Lint, MirLint, MirPass, WithMinOptLevel}; -mod abort_unwinding_calls; -mod add_call_guards; -mod add_moves_for_packed_drops; -mod add_retag; -mod add_subtyping_projections; -mod check_alignment; -mod check_const_item_mutation; -mod check_packed_ref; -mod check_undefined_transmutes; -// This pass is public to allow external drivers to perform MIR cleanup -pub mod cleanup_post_borrowck; -mod copy_prop; -mod coroutine; mod cost_checker; -mod coverage; mod cross_crate_inline; -mod ctfe_limit; -mod dataflow_const_prop; -mod dead_store_elimination; mod deduce_param_attrs; -mod deduplicate_blocks; -mod deref_separator; -mod dest_prop; -pub mod dump_mir; -mod early_otherwise_branch; -mod elaborate_box_derefs; -mod elaborate_drops; mod errors; mod ffi_unwind_calls; -mod function_item_references; -mod gvn; -// Made public so that `mir_drops_elaborated_and_const_checked` can be overridden -// by custom rustc drivers, running all the steps by themselves. See #114628. -pub mod inline; -mod instsimplify; -mod jump_threading; -mod known_panics_lint; -mod large_enums; mod lint; -mod lower_intrinsics; -mod lower_slice_len; -mod match_branches; -mod mentioned_items; -mod multiple_return_terminators; -mod nrvo; -mod post_drop_elaboration; -mod prettify; -mod promote_consts; -mod ref_prop; -mod remove_noop_landing_pads; -mod remove_place_mention; -mod remove_storage_markers; -mod remove_uninit_drops; -mod remove_unneeded_drops; -mod remove_zsts; -mod required_consts; -mod reveal_all; -mod sanity_check; mod shim; mod ssa; -// This pass is public to allow external drivers to perform MIR cleanup -pub mod simplify; -mod simplify_branches; -mod simplify_comparison_integral; -mod single_use_consts; -mod sroa; -mod unreachable_enum_branching; -mod unreachable_prop; -mod validate; + +/// We import passes via this macro so that we can have a static list of pass names +/// (used to verify CLI arguments). It takes a list of modules, followed by the passes +/// declared within them. +/// ```ignore,macro-test +/// declare_passes! { +/// // Declare a single pass from the module `abort_unwinding_calls` +/// mod abort_unwinding_calls : AbortUnwindingCalls; +/// // When passes are grouped together as an enum, declare the two constituent passes +/// mod add_call_guards : AddCallGuards { +/// AllCallEdges, +/// CriticalCallEdges +/// }; +/// // Declares multiple pass groups, each containing their own constituent passes +/// mod simplify : SimplifyCfg { +/// Initial, +/// /* omitted */ +/// }, SimplifyLocals { +/// BeforeConstProp, +/// /* omitted */ +/// }; +/// } +/// ``` +macro_rules! declare_passes { + ( + $( + $vis:vis mod $mod_name:ident : $($pass_name:ident $( { $($ident:ident),* } )?),+ $(,)?; + )* + ) => { + $( + $vis mod $mod_name; + $( + // Make sure the type name is correct + #[allow(unused_imports)] + use $mod_name::$pass_name as _; + )+ + )* + + #[cfg(debug_assertions)] + static PASS_NAMES: LazyLock> = LazyLock::new(|| vec![ + // Fake marker pass + "PreCodegen".to_string(), + $( + $( + stringify!($pass_name).to_string(), + $( + $( + $mod_name::$pass_name::$ident.name().to_string(), + )* + )? + )+ + )* + ]); + }; +} + +declare_passes! { + mod abort_unwinding_calls : AbortUnwindingCalls; + mod add_call_guards : AddCallGuards { AllCallEdges, CriticalCallEdges }; + mod add_moves_for_packed_drops : AddMovesForPackedDrops; + mod add_retag : AddRetag; + mod add_subtyping_projections : Subtyper; + mod check_alignment : CheckAlignment; + mod check_const_item_mutation : CheckConstItemMutation; + mod check_packed_ref : CheckPackedRef; + mod check_undefined_transmutes : CheckUndefinedTransmutes; + // This pass is public to allow external drivers to perform MIR cleanup + pub mod cleanup_post_borrowck : CleanupPostBorrowck; + + mod copy_prop : CopyProp; + mod coroutine : StateTransform; + mod coverage : InstrumentCoverage; + mod ctfe_limit : CtfeLimit; + mod dataflow_const_prop : DataflowConstProp; + mod dead_store_elimination : DeadStoreElimination { + Initial, + Final + }; + mod deduplicate_blocks : DeduplicateBlocks; + mod deref_separator : Derefer; + mod dest_prop : DestinationPropagation; + pub mod dump_mir : Marker; + mod early_otherwise_branch : EarlyOtherwiseBranch; + mod elaborate_box_derefs : ElaborateBoxDerefs; + mod elaborate_drops : ElaborateDrops; + mod function_item_references : FunctionItemReferences; + mod gvn : GVN; + // Made public so that `mir_drops_elaborated_and_const_checked` can be overridden + // by custom rustc drivers, running all the steps by themselves. See #114628. + pub mod inline : Inline; + mod instsimplify : InstSimplify { BeforeInline, AfterSimplifyCfg }; + mod jump_threading : JumpThreading; + mod known_panics_lint : KnownPanicsLint; + mod large_enums : EnumSizeOpt; + mod lower_intrinsics : LowerIntrinsics; + mod lower_slice_len : LowerSliceLenCalls; + mod match_branches : MatchBranchSimplification; + mod mentioned_items : MentionedItems; + mod multiple_return_terminators : MultipleReturnTerminators; + mod nrvo : RenameReturnPlace; + mod post_drop_elaboration : CheckLiveDrops; + mod prettify : ReorderBasicBlocks, ReorderLocals; + mod promote_consts : PromoteTemps; + mod ref_prop : ReferencePropagation; + mod remove_noop_landing_pads : RemoveNoopLandingPads; + mod remove_place_mention : RemovePlaceMention; + mod remove_storage_markers : RemoveStorageMarkers; + mod remove_uninit_drops : RemoveUninitDrops; + mod remove_unneeded_drops : RemoveUnneededDrops; + mod remove_zsts : RemoveZsts; + mod required_consts : RequiredConstsVisitor; + mod reveal_all : RevealAll; + mod sanity_check : SanityCheck; + // This pass is public to allow external drivers to perform MIR cleanup + pub mod simplify : + SimplifyCfg { + Initial, + PromoteConsts, + RemoveFalseEdges, + PostAnalysis, + PreOptimizations, + Final, + MakeShim, + AfterUnreachableEnumBranching + }, + SimplifyLocals { + BeforeConstProp, + AfterGVN, + Final + }; + mod simplify_branches : SimplifyConstCondition { + AfterConstProp, + Final + }; + mod simplify_comparison_integral : SimplifyComparisonIntegral; + mod single_use_consts : SingleUseConsts; + mod sroa : ScalarReplacementOfAggregates; + mod unreachable_enum_branching : UnreachableEnumBranching; + mod unreachable_prop : UnreachablePropagation; + mod validate : Validator; +} rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index 29f8b4f6e4d..37c9f5b4c21 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -1,7 +1,7 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_middle::mir::{self, Body, MirPhase, RuntimePhase}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -198,6 +198,16 @@ fn run_passes_inner<'tcx>( let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes; trace!(?overridden_passes); + #[cfg(debug_assertions)] + { + let used_passes: FxIndexSet<_> = passes.iter().map(|p| p.name()).collect(); + let known_passes: FxIndexSet<_> = crate::PASS_NAMES.iter().map(|p| p.as_str()).collect(); + + for &name in used_passes.difference(&known_passes) { + tcx.dcx().bug(format!("pass `{name}` is not declared in `PASS_NAMES`")); + } + } + let prof_arg = tcx.sess.prof.enabled().then(|| format!("{:?}", body.source.def_id())); if !body.should_skip() { From 94371d5a8cf3c0480a744e4727837e9d7b2281b0 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 11 Nov 2024 16:36:00 +0000 Subject: [PATCH 18/20] Validate and test `-Zmir-enable-passes` --- compiler/rustc_mir_transform/messages.ftl | 2 ++ compiler/rustc_mir_transform/src/errors.rs | 6 +++++ compiler/rustc_mir_transform/src/lib.rs | 1 - .../rustc_mir_transform/src/pass_manager.rs | 24 +++++++++++++++---- ...nable_passes_validation.all_unknown.stderr | 14 +++++++++++ .../mir/enable_passes_validation.empty.stderr | 2 ++ .../mir/enable_passes_validation.mixed.stderr | 8 +++++++ tests/ui/mir/enable_passes_validation.rs | 21 ++++++++++++++++ ...enable_passes_validation.unprefixed.stderr | 2 ++ 9 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 tests/ui/mir/enable_passes_validation.all_unknown.stderr create mode 100644 tests/ui/mir/enable_passes_validation.empty.stderr create mode 100644 tests/ui/mir/enable_passes_validation.mixed.stderr create mode 100644 tests/ui/mir/enable_passes_validation.rs create mode 100644 tests/ui/mir/enable_passes_validation.unprefixed.stderr diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index c8992b8b834..9bbfae17fd9 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -34,3 +34,5 @@ mir_transform_undefined_transmute = pointers cannot be transmuted to integers du .note = at compile-time, pointers do not have an integer value .note2 = avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior .help = for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html + +mir_transform_unknown_pass_name = MIR pass `{$name}` is unknown and will be ignored diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 8b309147c64..2d9eeddea2e 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -38,6 +38,12 @@ pub(crate) struct UnalignedPackedRef { pub span: Span, } +#[derive(Diagnostic)] +#[diag(mir_transform_unknown_pass_name)] +pub(crate) struct UnknownPassName<'a> { + pub(crate) name: &'a str, +} + pub(crate) struct AssertLint

{ pub span: Span, pub assert_kind: AssertKind

, diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 66ac3d30ca4..68904c65252 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -90,7 +90,6 @@ macro_rules! declare_passes { )+ )* - #[cfg(debug_assertions)] static PASS_NAMES: LazyLock> = LazyLock::new(|| vec![ // Fake marker pass "PreCodegen".to_string(), diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index 37c9f5b4c21..bc960ae0f56 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -8,7 +8,7 @@ use rustc_session::Session; use tracing::trace; use crate::lint::lint_body; -use crate::validate; +use crate::{errors, validate}; thread_local! { static PASS_NAMES: RefCell> = { @@ -198,13 +198,29 @@ fn run_passes_inner<'tcx>( let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes; trace!(?overridden_passes); + let named_passes: FxIndexSet<_> = + overridden_passes.iter().map(|(name, _)| name.as_str()).collect(); + let known_passes: FxIndexSet<_> = crate::PASS_NAMES.iter().map(|p| p.as_str()).collect(); + + for &name in named_passes.difference(&known_passes) { + tcx.dcx().emit_warn(errors::UnknownPassName { name }); + } + + // Verify that no passes are missing from the `declare_passes` invocation #[cfg(debug_assertions)] + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] { let used_passes: FxIndexSet<_> = passes.iter().map(|p| p.name()).collect(); - let known_passes: FxIndexSet<_> = crate::PASS_NAMES.iter().map(|p| p.as_str()).collect(); - for &name in used_passes.difference(&known_passes) { - tcx.dcx().bug(format!("pass `{name}` is not declared in `PASS_NAMES`")); + let undeclared = used_passes.difference(&known_passes).collect::>(); + if let Some((name, rest)) = undeclared.split_first() { + let mut err = + tcx.dcx().struct_bug(format!("pass `{name}` is not declared in `PASS_NAMES`")); + for name in rest { + err.note(format!("pass `{name}` is also not declared in `PASS_NAMES`")); + } + err.emit(); } } diff --git a/tests/ui/mir/enable_passes_validation.all_unknown.stderr b/tests/ui/mir/enable_passes_validation.all_unknown.stderr new file mode 100644 index 00000000000..85a942c00ed --- /dev/null +++ b/tests/ui/mir/enable_passes_validation.all_unknown.stderr @@ -0,0 +1,14 @@ +warning: MIR pass `ThisPass` is unknown and will be ignored + +warning: MIR pass `DoesNotExist` is unknown and will be ignored + +warning: MIR pass `ThisPass` is unknown and will be ignored + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: MIR pass `DoesNotExist` is unknown and will be ignored + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: 4 warnings emitted + diff --git a/tests/ui/mir/enable_passes_validation.empty.stderr b/tests/ui/mir/enable_passes_validation.empty.stderr new file mode 100644 index 00000000000..0e922663acc --- /dev/null +++ b/tests/ui/mir/enable_passes_validation.empty.stderr @@ -0,0 +1,2 @@ +error: incorrect value `` for unstable option `mir-enable-passes` - a comma-separated list of strings, with elements beginning with + or - was expected + diff --git a/tests/ui/mir/enable_passes_validation.mixed.stderr b/tests/ui/mir/enable_passes_validation.mixed.stderr new file mode 100644 index 00000000000..5aace86abc0 --- /dev/null +++ b/tests/ui/mir/enable_passes_validation.mixed.stderr @@ -0,0 +1,8 @@ +warning: MIR pass `ThisPassDoesNotExist` is unknown and will be ignored + +warning: MIR pass `ThisPassDoesNotExist` is unknown and will be ignored + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: 2 warnings emitted + diff --git a/tests/ui/mir/enable_passes_validation.rs b/tests/ui/mir/enable_passes_validation.rs new file mode 100644 index 00000000000..957e7d4d96d --- /dev/null +++ b/tests/ui/mir/enable_passes_validation.rs @@ -0,0 +1,21 @@ +//@ revisions: empty unprefixed all_unknown all_known mixed + +//@[empty] compile-flags: -Zmir-enable-passes= +//@[empty] error-pattern error: incorrect value `` for unstable option `mir-enable-passes` - a comma-separated list of strings, with elements beginning with + or - was expected + +//@[unprefixed] compile-flags: -Zmir-enable-passes=CheckAlignment +//@[unprefixed] error-pattern error: incorrect value `CheckAlignment` for unstable option `mir-enable-passes` - a comma-separated list of strings, with elements beginning with + or - was expected + +//@[all_unknown] check-pass +//@[all_unknown] compile-flags: -Zmir-enable-passes=+ThisPass,-DoesNotExist +//@[all_unknown] error-pattern: warning: MIR pass `ThisPass` is unknown and will be ignored +//@[all_unknown] error-pattern: warning: MIR pass `DoesNotExist` is unknown and will be ignored + +//@[all_known] check-pass +//@[all_known] compile-flags: -Zmir-enable-passes=+CheckAlignment,+LowerIntrinsics + +//@[mixed] check-pass +//@[mixed] compile-flags: -Zmir-enable-passes=+ThisPassDoesNotExist,+CheckAlignment +//@[mixed] error-pattern: warning: MIR pass `ThisPassDoesNotExist` is unknown and will be ignored + +fn main() {} diff --git a/tests/ui/mir/enable_passes_validation.unprefixed.stderr b/tests/ui/mir/enable_passes_validation.unprefixed.stderr new file mode 100644 index 00000000000..697589448f4 --- /dev/null +++ b/tests/ui/mir/enable_passes_validation.unprefixed.stderr @@ -0,0 +1,2 @@ +error: incorrect value `CheckAlignment` for unstable option `mir-enable-passes` - a comma-separated list of strings, with elements beginning with + or - was expected + From 12036830d039134c447a1d7299a59560cd4a39d0 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 11 Nov 2024 16:43:49 +0000 Subject: [PATCH 19/20] Store known passes as an IndexSet --- compiler/rustc_mir_transform/src/lib.rs | 10 +++++----- compiler/rustc_mir_transform/src/pass_manager.rs | 5 ++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 68904c65252..d2d5facbbdc 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -90,20 +90,20 @@ macro_rules! declare_passes { )+ )* - static PASS_NAMES: LazyLock> = LazyLock::new(|| vec![ + static PASS_NAMES: LazyLock> = LazyLock::new(|| [ // Fake marker pass - "PreCodegen".to_string(), + "PreCodegen", $( $( - stringify!($pass_name).to_string(), + stringify!($pass_name), $( $( - $mod_name::$pass_name::$ident.name().to_string(), + $mod_name::$pass_name::$ident.name(), )* )? )+ )* - ]); + ].into_iter().collect()); }; } diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index bc960ae0f56..e26e0c78b29 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -200,9 +200,8 @@ fn run_passes_inner<'tcx>( let named_passes: FxIndexSet<_> = overridden_passes.iter().map(|(name, _)| name.as_str()).collect(); - let known_passes: FxIndexSet<_> = crate::PASS_NAMES.iter().map(|p| p.as_str()).collect(); - for &name in named_passes.difference(&known_passes) { + for &name in named_passes.difference(&*crate::PASS_NAMES) { tcx.dcx().emit_warn(errors::UnknownPassName { name }); } @@ -213,7 +212,7 @@ fn run_passes_inner<'tcx>( { let used_passes: FxIndexSet<_> = passes.iter().map(|p| p.name()).collect(); - let undeclared = used_passes.difference(&known_passes).collect::>(); + let undeclared = used_passes.difference(&*crate::PASS_NAMES).collect::>(); if let Some((name, rest)) = undeclared.split_first() { let mut err = tcx.dcx().struct_bug(format!("pass `{name}` is not declared in `PASS_NAMES`")); From 8c64e9d17dad7d6e8a9f00191d8f55bd14b44aef Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 11 Nov 2024 16:51:39 +0000 Subject: [PATCH 20/20] Rename `PASS_NAMES` to disambiguate --- compiler/rustc_mir_transform/src/pass_manager.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index e26e0c78b29..779e7f22101 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -11,14 +11,15 @@ use crate::lint::lint_body; use crate::{errors, validate}; thread_local! { - static PASS_NAMES: RefCell> = { + /// Maps MIR pass names to a snake case form to match profiling naming style + static PASS_TO_PROFILER_NAMES: RefCell> = { RefCell::new(FxHashMap::default()) }; } /// Converts a MIR pass name into a snake case form to match the profiling naming style. fn to_profiler_name(type_name: &'static str) -> &'static str { - PASS_NAMES.with(|names| match names.borrow_mut().entry(type_name) { + PASS_TO_PROFILER_NAMES.with(|names| match names.borrow_mut().entry(type_name) { Entry::Occupied(e) => *e.get(), Entry::Vacant(e) => { let snake_case: String = type_name