Auto merge of #132954 - matthiaskrgr:rollup-x3rww9h, r=matthiaskrgr

Rollup of 7 pull requests

Successful merges:

 - #131831 (extend the "if-unchanged" logic for compiler builds)
 - #132541 (Proper support for cross-crate recursive const stability checks)
 - #132657 (AIX: add run-make support)
 - #132901 (Warn about invalid `mir-enable-passes` pass names)
 - #132923 (Triagebot: Consolidate the T-compiler ad hoc assignment groups)
 - #132938 (Make precise capturing suggestion machine-applicable only if it has no APITs)
 - #132947 (clarify `must_produce_diag` ICE for debugging)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-11-12 18:04:27 +00:00
commit f7273e0044
63 changed files with 753 additions and 348 deletions

View File

@ -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",

View File

@ -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<Symbol>,
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,36 +346,37 @@ 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
}
/// 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: 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(

View File

@ -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};
@ -709,6 +710,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 +724,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 +738,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
}
Some(ConstStability {
feature: Some(feature),
level: StabilityLevel::Unstable { .. },
feature,
..
}) => {
self.check_op(ops::IntrinsicUnstable {
@ -773,7 +776,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 +790,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
}
Some(ConstStability {
feature: Some(feature),
level: StabilityLevel::Unstable { implied_by: implied_feature, .. },
level: StabilityLevel::Unstable { implied_by: implied_feature, issue, .. },
feature,
..
}) => {
// An unstable const fn with a feature gate.
@ -810,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.

View File

@ -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 `-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()
&& (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())
}
@ -109,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
}
}
}

View File

@ -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}"
);
}
}

View File

@ -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 {

View File

@ -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

View File

@ -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<P> {
pub span: Span,
pub assert_kind: AssertKind<P>,

View File

@ -40,77 +40,158 @@ 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 _;
)+
)*
static PASS_NAMES: LazyLock<FxIndexSet<&str>> = LazyLock::new(|| [
// Fake marker pass
"PreCodegen",
$(
$(
stringify!($pass_name),
$(
$(
$mod_name::$pass_name::$ident.name(),
)*
)?
)+
)*
].into_iter().collect());
};
}
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" }

View File

@ -1,24 +1,25 @@
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;
use tracing::trace;
use crate::lint::lint_body;
use crate::validate;
use crate::{errors, validate};
thread_local! {
static PASS_NAMES: RefCell<FxHashMap<&'static str, &'static str>> = {
/// Maps MIR pass names to a snake case form to match profiling naming style
static PASS_TO_PROFILER_NAMES: RefCell<FxHashMap<&'static str, &'static str>> = {
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
@ -198,6 +199,31 @@ 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();
for &name in named_passes.difference(&*crate::PASS_NAMES) {
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 undeclared = used_passes.difference(&*crate::PASS_NAMES).collect::<Vec<_>>();
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();
}
}
let prof_arg = tcx.sess.prof.enabled().then(|| format!("{:?}", body.source.def_id()));
if !body.should_skip() {

View File

@ -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;
@ -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);
}
}
}
@ -161,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()
@ -289,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
});
@ -311,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,
@ -565,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
@ -582,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 });
}
@ -615,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)
}
@ -629,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);
}
@ -760,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

View File

@ -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(

View File

@ -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

View File

@ -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"

View File

@ -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";

View File

@ -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"]

View File

@ -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,
&[],
);

View File

@ -28,6 +28,24 @@ 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.
/// 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] = &[
":!src/tools",
":!tests",
":!triagebot.toml",
];
macro_rules! check_ci_llvm {
($name:expr) => {
assert!(
@ -2772,32 +2790,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 =

View File

@ -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};
@ -427,3 +427,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.");
}
}

View File

@ -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() {

View File

@ -176,9 +176,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

View File

@ -1011,9 +1011,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!(
"<a \
href=\"https://github.com/rust-lang/rust/issues/{n}\" \

View File

@ -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"] }

View File

@ -393,12 +393,8 @@ fn is_stable_const_fn(tcx: TyCtxt<'_>, 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()
}
})
}

View File

@ -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"

View File

@ -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",

View File

@ -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"] }

View File

@ -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"

View File

@ -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.
@ -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,18 +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++");
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
}
}

View File

@ -78,7 +78,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::{

View File

@ -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 {

View File

@ -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"

View File

@ -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" }

View File

@ -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" }

View File

@ -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<T>(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)]`
}
}

View File

@ -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<T>(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<T>(src: *const T, _dst: *mut T, _count: usize) {
|
error: aborting due to 8 previous errors

View File

@ -0,0 +1 @@
pub const fn just_a_fn() {}

View File

@ -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() {}

View File

@ -0,0 +1,21 @@
//@ 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 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")]
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() {}

View File

@ -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

View File

@ -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() };
}

View File

@ -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

View File

@ -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`

View File

@ -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

View File

@ -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

View File

@ -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() {}

View File

@ -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() {}

View File

@ -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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html>
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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -981,30 +981,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",