diff options
216 files changed, 1928 insertions, 1498 deletions
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 57ebab2abdf..eb71ec5f4ec 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -135,7 +135,7 @@ pub trait Visitor<'ast>: Sized { /// or `ControlFlow<T>`. type Result: VisitorResult = (); - fn visit_ident(&mut self, _ident: Ident) -> Self::Result { + fn visit_ident(&mut self, _ident: &'ast Ident) -> Self::Result { Self::Result::output() } fn visit_foreign_item(&mut self, i: &'ast ForeignItem) -> Self::Result { @@ -314,12 +314,12 @@ pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) -> V::R } pub fn walk_label<'a, V: Visitor<'a>>(visitor: &mut V, Label { ident }: &'a Label) -> V::Result { - visitor.visit_ident(*ident) + visitor.visit_ident(ident) } pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime) -> V::Result { let Lifetime { id: _, ident } = lifetime; - visitor.visit_ident(*ident) + visitor.visit_ident(ident) } pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, trait_ref: &'a PolyTraitRef) -> V::Result @@ -426,7 +426,7 @@ impl WalkItemKind for ItemKind { }) => { try_visit!(walk_qself(visitor, qself)); try_visit!(visitor.visit_path(path, *id)); - visit_opt!(visitor, visit_ident, *rename); + visit_opt!(visitor, visit_ident, rename); visit_opt!(visitor, visit_block, body); } ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { @@ -434,9 +434,9 @@ impl WalkItemKind for ItemKind { try_visit!(visitor.visit_path(prefix, *id)); if let Some(suffixes) = suffixes { for (ident, rename) in suffixes { - visitor.visit_ident(*ident); + visitor.visit_ident(ident); if let Some(rename) = rename { - visitor.visit_ident(*rename); + visitor.visit_ident(rename); } } } @@ -469,7 +469,7 @@ where let Variant { attrs, id: _, span: _, vis, ident, data, disr_expr, is_placeholder: _ } = variant; walk_list!(visitor, visit_attribute, attrs); try_visit!(visitor.visit_vis(vis)); - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_variant_data(data)); visit_opt!(visitor, visit_variant_discr, disr_expr); V::Result::output() @@ -478,7 +478,7 @@ where pub fn walk_expr_field<'a, V: Visitor<'a>>(visitor: &mut V, f: &'a ExprField) -> V::Result { let ExprField { attrs, id: _, span: _, ident, expr, is_shorthand: _, is_placeholder: _ } = f; walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_expr(expr)); V::Result::output() } @@ -486,7 +486,7 @@ pub fn walk_expr_field<'a, V: Visitor<'a>>(visitor: &mut V, f: &'a ExprField) -> pub fn walk_pat_field<'a, V: Visitor<'a>>(visitor: &mut V, fp: &'a PatField) -> V::Result { let PatField { ident, pat, is_shorthand: _, attrs, id: _, span: _, is_placeholder: _ } = fp; walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_pat(pat)); V::Result::output() } @@ -561,7 +561,7 @@ pub fn walk_use_tree<'a, V: Visitor<'a>>( match kind { UseTreeKind::Simple(rename) => { // The extra IDs are handled during AST lowering. - visit_opt!(visitor, visit_ident, *rename); + visit_opt!(visitor, visit_ident, rename); } UseTreeKind::Glob => {} UseTreeKind::Nested { ref items, span: _ } => { @@ -578,7 +578,7 @@ pub fn walk_path_segment<'a, V: Visitor<'a>>( segment: &'a PathSegment, ) -> V::Result { let PathSegment { ident, id: _, args } = segment; - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); visit_opt!(visitor, visit_generic_args, args); V::Result::output() } @@ -624,7 +624,7 @@ pub fn walk_assoc_item_constraint<'a, V: Visitor<'a>>( constraint: &'a AssocItemConstraint, ) -> V::Result { let AssocItemConstraint { id: _, ident, gen_args, kind, span: _ } = constraint; - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); visit_opt!(visitor, visit_generic_args, gen_args); match kind { AssocItemConstraintKind::Equality { term } => match term { @@ -662,7 +662,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res try_visit!(visitor.visit_pat(subpattern)); } PatKind::Ident(_bmode, ident, optional_subpattern) => { - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); visit_opt!(visitor, visit_pat, optional_subpattern); } PatKind::Lit(expression) => try_visit!(visitor.visit_expr(expression)), @@ -748,7 +748,7 @@ pub fn walk_generic_param<'a, V: Visitor<'a>>( let GenericParam { id: _, ident, attrs, bounds, is_placeholder: _, kind, colon_span: _ } = param; walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); match kind { GenericParamKind::Lifetime => (), @@ -886,7 +886,7 @@ impl WalkItemKind for AssocItemKind { }) => { try_visit!(walk_qself(visitor, qself)); try_visit!(visitor.visit_path(path, *id)); - visit_opt!(visitor, visit_ident, *rename); + visit_opt!(visitor, visit_ident, rename); visit_opt!(visitor, visit_block, body); } AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { @@ -894,9 +894,9 @@ impl WalkItemKind for AssocItemKind { try_visit!(visitor.visit_path(prefix, id)); if let Some(suffixes) = suffixes { for (ident, rename) in suffixes { - visitor.visit_ident(*ident); + visitor.visit_ident(ident); if let Some(rename) = rename { - visitor.visit_ident(*rename); + visitor.visit_ident(rename); } } } @@ -912,7 +912,7 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>( item: &'a Item<impl WalkItemKind>, ctxt: AssocCtxt, ) -> V::Result { - let &Item { id: _, span: _, ident, ref vis, ref attrs, ref kind, tokens: _ } = item; + let Item { id: _, span: _, ident, vis, attrs, kind, tokens: _ } = item; walk_list!(visitor, visit_attribute, attrs); try_visit!(visitor.visit_vis(vis)); try_visit!(visitor.visit_ident(ident)); @@ -932,7 +932,7 @@ pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef) let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _ } = field; walk_list!(visitor, visit_attribute, attrs); try_visit!(visitor.visit_vis(vis)); - visit_opt!(visitor, visit_ident, *ident); + visit_opt!(visitor, visit_ident, ident); try_visit!(visitor.visit_ty(ty)); V::Result::output() } @@ -1014,7 +1014,7 @@ pub fn walk_format_args<'a, V: Visitor<'a>>(visitor: &mut V, fmt: &'a FormatArgs for FormatArgument { kind, expr } in arguments.all_args() { match kind { FormatArgumentKind::Named(ident) | FormatArgumentKind::Captured(ident) => { - try_visit!(visitor.visit_ident(*ident)) + try_visit!(visitor.visit_ident(ident)) } FormatArgumentKind::Normal => {} } @@ -1134,7 +1134,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V } ExprKind::Field(subexpression, ident) => { try_visit!(visitor.visit_expr(subexpression)); - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); } ExprKind::Index(main_expression, index_expression, _span) => { try_visit!(visitor.visit_expr(main_expression)); @@ -1169,7 +1169,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V ExprKind::FormatArgs(f) => try_visit!(visitor.visit_format_args(f)), ExprKind::OffsetOf(container, fields) => { try_visit!(visitor.visit_ty(container)); - walk_list!(visitor, visit_ident, fields.iter().copied()); + walk_list!(visitor, visit_ident, fields.iter()); } ExprKind::Yield(optional_expression) => { visit_opt!(visitor, visit_expr, optional_expression); diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index bf6ebfb160b..1d149e91b85 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -249,7 +249,7 @@ impl<'a> AstValidator<'a> { } fn visit_struct_field_def(&mut self, field: &'a FieldDef) { - if let Some(ident) = field.ident + if let Some(ref ident) = field.ident && ident.name == kw::Underscore { self.visit_vis(&field.vis); @@ -899,7 +899,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } this.visit_vis(&item.vis); - this.visit_ident(item.ident); + this.visit_ident(&item.ident); let disallowed = matches!(constness, Const::No) .then(|| TildeConstReason::TraitImpl { span: item.span }); this.with_tilde_const(disallowed, |this| this.visit_generics(generics)); @@ -953,7 +953,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } this.visit_vis(&item.vis); - this.visit_ident(item.ident); + this.visit_ident(&item.ident); this.with_tilde_const( Some(TildeConstReason::Impl { span: item.span }), |this| this.visit_generics(generics), @@ -991,7 +991,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } self.visit_vis(&item.vis); - self.visit_ident(item.ident); + self.visit_ident(&item.ident); let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref()); self.visit_fn(kind, item.span, item.id); @@ -1058,7 +1058,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound // context for the supertraits. this.visit_vis(&item.vis); - this.visit_ident(item.ident); + this.visit_ident(&item.ident); let disallowed = is_const_trait .is_none() .then(|| TildeConstReason::Trait { span: item.span }); @@ -1085,7 +1085,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ItemKind::Struct(vdata, generics) => match vdata { VariantData::Struct { fields, .. } => { self.visit_vis(&item.vis); - self.visit_ident(item.ident); + self.visit_ident(&item.ident); self.visit_generics(generics); // Permit `Anon{Struct,Union}` as field type. walk_list!(self, visit_struct_field_def, fields); @@ -1101,7 +1101,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { match vdata { VariantData::Struct { fields, .. } => { self.visit_vis(&item.vis); - self.visit_ident(item.ident); + self.visit_ident(&item.ident); self.visit_generics(generics); // Permit `Anon{Struct,Union}` as field type. walk_list!(self, visit_struct_field_def, fields); @@ -1521,7 +1521,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { || matches!(sig.header.constness, Const::Yes(_)) => { self.visit_vis(&item.vis); - self.visit_ident(item.ident); + self.visit_ident(&item.ident); let kind = FnKind::Fn( FnCtxt::Assoc(ctxt), item.ident, diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 348a602fd59..d646150a620 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -623,8 +623,9 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) let stable_since = features .enabled_lang_features() .iter() - .flat_map(|&(feature, _, since)| if feature == name { since } else { None }) - .next(); + .find(|feat| feat.gate_name == name) + .map(|feat| feat.stable_since) + .flatten(); if let Some(since) = stable_since { err.stable_features.push(errors::StableFeature { name, since }); } else { @@ -642,16 +643,15 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) } fn check_incompatible_features(sess: &Session, features: &Features) { - let enabled_features = features - .enabled_lang_features() - .iter() - .copied() - .map(|(name, span, _)| (name, span)) - .chain(features.enabled_lib_features().iter().copied()); + let enabled_lang_features = + features.enabled_lang_features().iter().map(|feat| (feat.gate_name, feat.attr_sp)); + let enabled_lib_features = + features.enabled_lib_features().iter().map(|feat| (feat.gate_name, feat.attr_sp)); + let enabled_features = enabled_lang_features.chain(enabled_lib_features); for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES .iter() - .filter(|&&(f1, f2)| features.enabled(f1) && features.enabled(f2)) + .filter(|(f1, f2)| features.enabled(*f1) && features.enabled(*f2)) { if let Some((f1_name, f1_span)) = enabled_features.clone().find(|(name, _)| name == f1) { if let Some((f2_name, f2_span)) = enabled_features.clone().find(|(name, _)| name == f2) @@ -673,10 +673,11 @@ fn check_new_solver_banned_features(sess: &Session, features: &Features) { } // Ban GCE with the new solver, because it does not implement GCE correctly. - if let Some(&(_, gce_span, _)) = features + if let Some(gce_span) = features .enabled_lang_features() .iter() - .find(|&&(feat, _, _)| feat == sym::generic_const_exprs) + .find(|feat| feat.gate_name == sym::generic_const_exprs) + .map(|feat| feat.attr_sp) { sess.dcx().emit_err(errors::IncompatibleFeatures { spans: vec![gce_span], diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs index e22e99f6e4d..9e7204df8ad 100644 --- a/compiler/rustc_ast_passes/src/node_count.rs +++ b/compiler/rustc_ast_passes/src/node_count.rs @@ -16,7 +16,7 @@ impl NodeCounter { } impl<'ast> Visitor<'ast> for NodeCounter { - fn visit_ident(&mut self, _ident: Ident) { + fn visit_ident(&mut self, _ident: &Ident) { self.count += 1; } fn visit_foreign_item(&mut self, i: &ForeignItem) { diff --git a/compiler/rustc_attr/messages.ftl b/compiler/rustc_attr/messages.ftl index adabf18ca85..235ab7572c4 100644 --- a/compiler/rustc_attr/messages.ftl +++ b/compiler/rustc_attr/messages.ftl @@ -91,6 +91,9 @@ attr_non_ident_feature = attr_rustc_allowed_unstable_pairing = `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute +attr_rustc_const_stable_indirect_pairing = + `const_stable_indirect` attribute does not make sense on `rustc_const_stable` function, its behavior is already implied + attr_rustc_promotable_pairing = `rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 537d8e04531..6af75bc94bb 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,7 +92,11 @@ impl Stability { #[derive(HashStable_Generic)] pub struct ConstStability { pub level: StabilityLevel, - pub feature: Symbol, + /// 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>, + /// This is true iff the `const_stable_indirect` attribute is present. + pub const_stable_indirect: bool, /// whether the function has a `#[rustc_promotable]` attribute pub promotable: bool, } @@ -268,17 +272,23 @@ 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`. It will always +/// be false for intrinsics in an `extern` block! 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; 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_unstable => { if const_stab.is_some() { sess.dcx() @@ -287,8 +297,15 @@ pub fn find_const_stability( } if let Some((feature, level)) = parse_unstability(sess, attr) { - const_stab = - Some((ConstStability { level, feature, promotable: false }, attr.span)); + const_stab = Some(( + ConstStability { + level, + feature: Some(feature), + const_stable_indirect: false, + promotable: false, + }, + attr.span, + )); } } sym::rustc_const_stable => { @@ -298,15 +315,22 @@ pub fn find_const_stability( break; } if let Some((feature, level)) = parse_stability(sess, attr) { - const_stab = - Some((ConstStability { level, feature, promotable: false }, attr.span)); + const_stab = Some(( + ConstStability { + level, + feature: Some(feature), + const_stable_indirect: false, + promotable: false, + }, + attr.span, + )); } } _ => {} } } - // Merge the const-unstable info into the stability info + // Merge promotable and not_exposed_on_stable into stability info if promotable { match &mut const_stab { Some((stab, _)) => stab.promotable = promotable, @@ -317,6 +341,46 @@ pub fn find_const_stability( } } } + if const_stable_indirect.is_some() { + match &mut const_stab { + Some((stab, _)) => { + if stab.is_const_unstable() { + stab.const_stable_indirect = true; + } else { + _ = sess.dcx().emit_err(session_diagnostics::RustcConstStableIndirectPairing { + span: item_sp, + }) + } + } + _ => { + // We ignore the `#[rustc_const_stable_indirect]` here, it should be picked up by + // the `default_const_unstable` logic. + } + } + } + // 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 } diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index 626840aa6a3..9d08a9f5754 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -319,6 +319,13 @@ pub(crate) struct RustcPromotablePairing { } #[derive(Diagnostic)] +#[diag(attr_rustc_const_stable_indirect_pairing)] +pub(crate) struct RustcConstStableIndirectPairing { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(attr_rustc_allowed_unstable_pairing, code = E0789)] pub(crate) struct RustcAllowedUnstablePairing { #[primary_span] diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 652e6f7740f..d4befd12190 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -222,7 +222,7 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, ' rustc_ast::visit::walk_attribute(self, attr); } fn visit_variant(&mut self, v: &'a rustc_ast::Variant) { - self.visit_ident(v.ident); + self.visit_ident(&v.ident); self.visit_vis(&v.vis); self.visit_variant_data(&v.data); visit_opt!(self, visit_anon_const, &v.disr_expr); diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index d6603af101a..707c36d5046 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -313,14 +313,23 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> { match m { ProcMacro::Derive(cd) => { cx.resolver.declare_proc_macro(cd.id); - cx.expr_call(span, proc_macro_ty_method_path(cx, custom_derive), thin_vec![ - cx.expr_str(span, cd.trait_name), - cx.expr_array_ref( - span, - cd.attrs.iter().map(|&s| cx.expr_str(span, s)).collect::<ThinVec<_>>(), - ), - local_path(cx, cd.function_name), - ]) + // The call needs to use `harness_span` so that the const stability checker + // accepts it. + cx.expr_call( + harness_span, + proc_macro_ty_method_path(cx, custom_derive), + thin_vec![ + cx.expr_str(span, cd.trait_name), + cx.expr_array_ref( + span, + cd.attrs + .iter() + .map(|&s| cx.expr_str(span, s)) + .collect::<ThinVec<_>>(), + ), + local_path(cx, cd.function_name), + ], + ) } ProcMacro::Attr(ca) | ProcMacro::Bang(ca) => { cx.resolver.declare_proc_macro(ca.id); @@ -330,7 +339,9 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> { ProcMacro::Derive(_) => unreachable!(), }; - cx.expr_call(span, proc_macro_ty_method_path(cx, ident), thin_vec![ + // The call needs to use `harness_span` so that the const stability checker + // accepts it. + cx.expr_call(harness_span, proc_macro_ty_method_path(cx, ident), thin_vec![ cx.expr_str(span, ca.function_name.name), local_path(cx, ca.function_name), ]) diff --git a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch index 646928893e9..3c81b04c0ea 100644 --- a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch +++ b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch @@ -38,7 +38,7 @@ diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index d9de37e..8293fce 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs -@@ -2996,42 +2996,6 @@ atomic_int! { +@@ -2996,44 +2996,6 @@ atomic_int! { 8, u64 AtomicU64 } @@ -52,7 +52,8 @@ index d9de37e..8293fce 100644 - unstable(feature = "integer_atomics", issue = "99069"), - unstable(feature = "integer_atomics", issue = "99069"), - unstable(feature = "integer_atomics", issue = "99069"), -- rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), +- rustc_const_unstable(feature = "integer_atomics", issue = "99069"), +- rustc_const_unstable(feature = "integer_atomics", issue = "99069"), - cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"), - "i128", - "#![feature(integer_atomics)]\n\n", @@ -70,7 +71,8 @@ index d9de37e..8293fce 100644 - unstable(feature = "integer_atomics", issue = "99069"), - unstable(feature = "integer_atomics", issue = "99069"), - unstable(feature = "integer_atomics", issue = "99069"), -- rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), +- rustc_const_unstable(feature = "integer_atomics", issue = "99069"), +- rustc_const_unstable(feature = "integer_atomics", issue = "99069"), - cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"), - "u128", - "#![feature(integer_atomics)]\n\n", diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index f0b78e5d7c6..79d76925df9 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -210,7 +210,6 @@ impl DebugContext { type_names::push_generic_params( tcx, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args), - enclosing_fn_def_id, &mut name, ); diff --git a/compiler/rustc_codegen_gcc/src/callee.rs b/compiler/rustc_codegen_gcc/src/callee.rs index 9ad2e90122f..65972a03e83 100644 --- a/compiler/rustc_codegen_gcc/src/callee.rs +++ b/compiler/rustc_codegen_gcc/src/callee.rs @@ -98,8 +98,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) // whether we are sharing generics or not. The important thing here is // that the visibility we apply to the declaration is the same one that // has been applied to the definition (wherever that definition may be). - let is_generic = - instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some(); + let is_generic = instance.args.non_erasable_generics().next().is_some(); if is_generic { // This is a monomorphization. Its expected visibility depends diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index 206a7069792..a51ef8d7b85 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -98,8 +98,7 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); - let is_generic = - instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some(); + let is_generic = instance.args.non_erasable_generics().next().is_some(); let is_hidden = if is_generic { // This is a monomorphization of a generic function. diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 1a8153a54e8..3de4ca77e7d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -350,7 +350,6 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { type_names::push_generic_params( tcx, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args), - enclosing_fn_def_id, &mut name, ); diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 77c35a1fe79..d9669453f5a 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -312,7 +312,7 @@ fn exported_symbols_provider_local( match *mono_item { MonoItem::Fn(Instance { def: InstanceKind::Item(def), args }) => { - if args.non_erasable_generics(tcx, def).next().is_some() { + if args.non_erasable_generics().next().is_some() { let symbol = ExportedSymbol::Generic(def, args); symbols.push((symbol, SymbolExportInfo { level: SymbolExportLevel::Rust, @@ -321,12 +321,9 @@ fn exported_symbols_provider_local( })); } } - MonoItem::Fn(Instance { def: InstanceKind::DropGlue(def_id, Some(ty)), args }) => { + MonoItem::Fn(Instance { def: InstanceKind::DropGlue(_, Some(ty)), args }) => { // A little sanity-check - assert_eq!( - args.non_erasable_generics(tcx, def_id).next(), - Some(GenericArgKind::Type(ty)) - ); + assert_eq!(args.non_erasable_generics().next(), Some(GenericArgKind::Type(ty))); symbols.push((ExportedSymbol::DropGlue(ty), SymbolExportInfo { level: SymbolExportLevel::Rust, kind: SymbolExportKind::Text, @@ -334,14 +331,11 @@ fn exported_symbols_provider_local( })); } MonoItem::Fn(Instance { - def: InstanceKind::AsyncDropGlueCtorShim(def_id, Some(ty)), + def: InstanceKind::AsyncDropGlueCtorShim(_, Some(ty)), args, }) => { // A little sanity-check - assert_eq!( - args.non_erasable_generics(tcx, def_id).next(), - Some(GenericArgKind::Type(ty)) - ); + assert_eq!(args.non_erasable_generics().next(), Some(GenericArgKind::Type(ty))); symbols.push((ExportedSymbol::AsyncDropGlueCtorShim(ty), SymbolExportInfo { level: SymbolExportLevel::Rust, kind: SymbolExportKind::Text, diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 526d2b86d48..1e5b4f3433d 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -110,14 +110,14 @@ fn push_debuginfo_type_name<'tcx>( ty_and_layout, &|output, visited| { push_item_name(tcx, def.did(), true, output); - push_generic_params_internal(tcx, args, def.did(), output, visited); + push_generic_params_internal(tcx, args, output, visited); }, output, visited, ); } else { push_item_name(tcx, def.did(), qualified, output); - push_generic_params_internal(tcx, args, def.did(), output, visited); + push_generic_params_internal(tcx, args, output, visited); } } ty::Tuple(component_types) => { @@ -251,13 +251,8 @@ fn push_debuginfo_type_name<'tcx>( let principal = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), principal); push_item_name(tcx, principal.def_id, qualified, output); - let principal_has_generic_params = push_generic_params_internal( - tcx, - principal.args, - principal.def_id, - output, - visited, - ); + let principal_has_generic_params = + push_generic_params_internal(tcx, principal.args, output, visited); let projection_bounds: SmallVec<[_; 4]> = trait_data .projection_bounds() @@ -538,13 +533,7 @@ pub fn compute_debuginfo_vtable_name<'tcx>( tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref); push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name); visited.clear(); - push_generic_params_internal( - tcx, - trait_ref.args, - trait_ref.def_id, - &mut vtable_name, - &mut visited, - ); + push_generic_params_internal(tcx, trait_ref.args, &mut vtable_name, &mut visited); } else { vtable_name.push('_'); } @@ -647,12 +636,11 @@ fn push_unqualified_item_name( fn push_generic_params_internal<'tcx>( tcx: TyCtxt<'tcx>, args: GenericArgsRef<'tcx>, - def_id: DefId, output: &mut String, visited: &mut FxHashSet<Ty<'tcx>>, ) -> bool { assert_eq!(args, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args)); - let mut args = args.non_erasable_generics(tcx, def_id).peekable(); + let mut args = args.non_erasable_generics().peekable(); if args.peek().is_none() { return false; } @@ -736,12 +724,11 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S pub fn push_generic_params<'tcx>( tcx: TyCtxt<'tcx>, args: GenericArgsRef<'tcx>, - def_id: DefId, output: &mut String, ) { let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name"); let mut visited = FxHashSet::default(); - push_generic_params_internal(tcx, args, def_id, output, &mut visited); + push_generic_params_internal(tcx, args, output, &mut visited); } fn push_closure_or_coroutine_name<'tcx>( @@ -786,7 +773,7 @@ fn push_closure_or_coroutine_name<'tcx>( // FIXME(async_closures): This is probably not going to be correct w.r.t. // multiple coroutine flavors. Maybe truncate to (parent + 1)? let args = args.truncate_to(tcx, generics); - push_generic_params_internal(tcx, args, enclosing_fn_def_id, output, visited); + push_generic_params_internal(tcx, args, output, visited); } fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) { diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 24dbe688f36..3e4f83c8242 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -41,8 +41,6 @@ const_eval_const_context = {$kind -> *[other] {""} } -const_eval_const_stable = const-stable functions can only call other const-stable functions - const_eval_copy_nonoverlapping_overlapping = `copy_nonoverlapping` called on overlapping ranges @@ -259,6 +257,9 @@ const_eval_non_const_fn_call = const_eval_non_const_impl = impl defined here, but it is not `const` +const_eval_non_const_intrinsic = + cannot call non-const intrinsic `{$name}` in {const_eval_const_context}s + const_eval_not_enough_caller_args = calling a function with fewer arguments than it requires @@ -397,17 +398,29 @@ const_eval_uninhabited_enum_variant_read = read discriminant of an uninhabited enum variant const_eval_uninhabited_enum_variant_written = writing discriminant of an uninhabited enum variant + +const_eval_unmarked_const_fn_exposed = `{$def_path}` cannot be (indirectly) exposed to stable + .help = either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]` +const_eval_unmarked_intrinsic_exposed = intrinsic `{$def_path}` cannot be (indirectly) exposed to stable + .help = mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval) + const_eval_unreachable = entering unreachable code const_eval_unreachable_unwind = unwinding past a stack frame that does not allow unwinding const_eval_unsized_local = unsized locals are not supported const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn - -const_eval_unstable_in_stable = - const-stable function cannot use `#[feature({$gate})]` - .unstable_sugg = if the function is not (yet) meant to be stable, make this function unstably const - .bypass_sugg = otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (but requires team approval) +const_eval_unstable_in_stable_exposed = + const function that might be (indirectly) exposed to stable cannot use `#[feature({$gate})]` + .is_function_call = mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features + .unstable_sugg = if the {$is_function_call2 -> + [true] caller + *[false] function + } is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + .bypass_sugg = otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + +const_eval_unstable_intrinsic = `{$name}` is not yet stable as a const intrinsic + .help = add `#![feature({$feature})]` to the crate attributes to enable const_eval_unterminated_c_string = reading a null-terminated string starting at {$pointer} with no null found before end of allocation diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 288798bf0c2..8f1a887a961 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -5,6 +5,7 @@ use std::borrow::Cow; use std::mem; use std::ops::Deref; +use rustc_attr::{ConstStability, StabilityLevel}; use rustc_errors::{Diag, ErrorGuaranteed}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, LangItem}; @@ -28,8 +29,8 @@ use super::ops::{self, NonConstOp, Status}; use super::qualifs::{self, HasMutInterior, NeedsDrop, NeedsNonConstDrop}; use super::resolver::FlowSensitiveAnalysis; use super::{ConstCx, Qualif}; -use crate::const_eval::is_unstable_const_fn; -use crate::errors::UnstableInStable; +use crate::check_consts::is_safe_to_expose_on_stable_const_fn; +use crate::errors; type QualifResults<'mir, 'tcx, Q> = rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>; @@ -274,19 +275,22 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { /// context. pub fn check_op_spanned<O: NonConstOp<'tcx>>(&mut self, op: O, span: Span) { let gate = match op.status_in_item(self.ccx) { - Status::Allowed => return, - - Status::Unstable(gate) if self.tcx.features().enabled(gate) => { - let unstable_in_stable = self.ccx.is_const_stable_const_fn() - && !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate); - if unstable_in_stable { - emit_unstable_in_stable_error(self.ccx, span, gate); + Status::Unstable { gate, safe_to_expose_on_stable, is_function_call } + if self.tcx.features().enabled(gate) => + { + // Generally this is allowed since the feature gate is enabled -- except + // if this function wants to be safe-to-expose-on-stable. + if !safe_to_expose_on_stable + && self.enforce_recursive_const_stability() + && !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate) + { + emit_unstable_in_stable_exposed_error(self.ccx, span, gate, is_function_call); } return; } - Status::Unstable(gate) => Some(gate), + Status::Unstable { gate, .. } => Some(gate), Status::Forbidden => None, }; @@ -304,7 +308,13 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { self.error_emitted = Some(reported); } - ops::DiagImportance::Secondary => self.secondary_errors.push(err), + ops::DiagImportance::Secondary => { + self.secondary_errors.push(err); + self.tcx.dcx().span_delayed_bug( + span, + "compilation must fail when there is a secondary const checker error", + ); + } } } @@ -569,6 +579,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { ty::FnPtr(..) => { self.check_op(ops::FnCallIndirect); + // We can get here without an error in miri-unleashed mode... might as well + // skip the rest of the checks as well then. return; } _ => { @@ -612,6 +624,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // checks. // FIXME(effects) we might consider moving const stability checks to typeck as well. if tcx.features().effects() { + // This skips the check below that ensures we only call `const fn`. is_trait = true; if let Ok(Some(instance)) = @@ -637,6 +650,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { sym::const_trait_impl }), }); + // If we allowed this, we're in miri-unleashed mode, so we might + // as well skip the remaining checks. return; } } @@ -650,29 +665,73 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // const-eval of the `begin_panic` fn assumes the argument is `&str` if tcx.is_lang_item(callee, LangItem::BeginPanic) { match args[0].node.ty(&self.ccx.body.local_decls, tcx).kind() { - ty::Ref(_, ty, _) if ty.is_str() => return, + ty::Ref(_, ty, _) if ty.is_str() => {} _ => self.check_op(ops::PanicNonStr), } + // Allow this call, skip all the checks below. + return; } // const-eval of `#[rustc_const_panic_str]` functions assumes the argument is `&&str` if tcx.has_attr(callee, sym::rustc_const_panic_str) { match args[0].node.ty(&self.ccx.body.local_decls, tcx).kind() { ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) => - { - return; + {} + _ => { + self.check_op(ops::PanicNonStr); } - _ => self.check_op(ops::PanicNonStr), } + // Allow this call, skip all the checks below. + return; } // This can be called on stable via the `vec!` macro. if tcx.is_lang_item(callee, LangItem::ExchangeMalloc) { self.check_op(ops::HeapAllocation); + // Allow this call, skip all the checks below. return; } - if !tcx.is_const_fn_raw(callee) && !is_trait { + // Intrinsics are language primitives, not regular calls, so treat them separately. + if let Some(intrinsic) = tcx.intrinsic(callee) { + match tcx.lookup_const_stability(callee) { + None => { + // Non-const intrinsic. + self.check_op(ops::IntrinsicNonConst { name: intrinsic.name }); + } + Some(ConstStability { feature: None, const_stable_indirect, .. }) => { + // Intrinsic does not need a separate feature gate (we rely on the + // regular stability checker). However, we have to worry about recursive + // const stability. + if !const_stable_indirect && self.enforce_recursive_const_stability() { + self.dcx().emit_err(errors::UnmarkedIntrinsicExposed { + span: self.span, + def_path: self.tcx.def_path_str(callee), + }); + } + } + Some(ConstStability { + feature: Some(feature), + level: StabilityLevel::Unstable { .. }, + const_stable_indirect, + .. + }) => { + self.check_op(ops::IntrinsicUnstable { + name: intrinsic.name, + feature, + const_stable_indirect, + }); + } + Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => { + // All good. + } + } + // This completes the checks for intrinsics. + return; + } + + // Trait functions are not `const fn` so we have to skip them here. + if !tcx.is_const_fn(callee) && !is_trait { self.check_op(ops::FnCallNonConst { caller, callee, @@ -681,66 +740,68 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { call_source, feature: None, }); + // If we allowed this, we're in miri-unleashed mode, so we might + // as well skip the remaining checks. return; } - // If the `const fn` we are trying to call is not const-stable, ensure that we have - // the proper feature gate enabled. - if let Some((gate, implied_by)) = is_unstable_const_fn(tcx, callee) { - trace!(?gate, "calling unstable const fn"); - if self.span.allows_unstable(gate) { - return; + // Finally, stability for regular function calls -- this is the big one. + match tcx.lookup_const_stability(callee) { + Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => { + // All good. } - if let Some(implied_by_gate) = implied_by - && self.span.allows_unstable(implied_by_gate) - { - return; - } - - // Calling an unstable function *always* requires that the corresponding gate - // (or implied gate) be enabled, even if the function has - // `#[rustc_allow_const_fn_unstable(the_gate)]`. - let gate_enabled = |gate| tcx.features().enabled(gate); - let feature_gate_enabled = gate_enabled(gate); - let implied_gate_enabled = implied_by.is_some_and(gate_enabled); - if !feature_gate_enabled && !implied_gate_enabled { - self.check_op(ops::FnCallUnstable(callee, Some(gate))); - return; - } - - // If this crate is not using stability attributes, or the caller is not claiming to be a - // stable `const fn`, that is all that is required. - if !self.ccx.is_const_stable_const_fn() { - trace!("crate not using stability attributes or caller not stably const"); - return; - } - - // Otherwise, we are something const-stable calling a const-unstable fn. - if super::rustc_allow_const_fn_unstable(tcx, caller, gate) { - trace!("rustc_allow_const_fn_unstable gate enabled"); - return; + None | Some(ConstStability { feature: 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. + if self.enforce_recursive_const_stability() + && !is_safe_to_expose_on_stable_const_fn(tcx, callee) + { + self.dcx().emit_err(errors::UnmarkedConstFnExposed { + span: self.span, + def_path: self.tcx.def_path_str(callee), + }); + } } + Some(ConstStability { + feature: Some(feature), + level: StabilityLevel::Unstable { implied_by: implied_feature, .. }, + .. + }) => { + // An unstable const fn with a feature gate. + let callee_safe_to_expose_on_stable = + is_safe_to_expose_on_stable_const_fn(tcx, callee); + + // We only honor `span.allows_unstable` aka `#[allow_internal_unstable]` if + // the callee is safe to expose, to avoid bypassing recursive stability. + if (self.span.allows_unstable(feature) + || implied_feature.is_some_and(|f| self.span.allows_unstable(f))) + && callee_safe_to_expose_on_stable + { + return; + } - self.check_op(ops::FnCallUnstable(callee, Some(gate))); - return; - } - - // FIXME(ecstaticmorse); For compatibility, we consider `unstable` callees that - // have no `rustc_const_stable` attributes to be const-unstable as well. This - // should be fixed later. - let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none() - && tcx.lookup_stability(callee).is_some_and(|s| s.is_unstable()); - if callee_is_unstable_unmarked { - trace!("callee_is_unstable_unmarked"); - // We do not use `const` modifiers for intrinsic "functions", as intrinsics are - // `extern` functions, and these have no way to get marked `const`. So instead we - // use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const` - if self.ccx.is_const_stable_const_fn() || tcx.intrinsic(callee).is_some() { - self.check_op(ops::FnCallUnstable(callee, None)); - return; + // We can't use `check_op` to check whether the feature is enabled because + // the logic is a bit different than elsewhere: local functions don't need + // the feature gate, and there might be an "implied" gate that also suffices + // to allow this. + let feature_enabled = callee.is_local() + || tcx.features().enabled(feature) + || implied_feature.is_some_and(|f| tcx.features().enabled(f)); + // 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. + let danger_zone = !callee_safe_to_expose_on_stable + && self.enforce_recursive_const_stability(); + if danger_zone || !feature_enabled { + self.check_op(ops::FnCallUnstable { + def_id: callee, + feature, + safe_to_expose_on_stable: callee_safe_to_expose_on_stable, + }); + } } } - trace!("permitting call"); } // Forbid all `Drop` terminators unless the place being dropped is a local with no @@ -785,11 +846,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm), - TerminatorKind::Yield { .. } => self.check_op(ops::Coroutine( - self.tcx - .coroutine_kind(self.body.source.def_id()) - .expect("Only expected to have a yield in a coroutine"), - )), + TerminatorKind::Yield { .. } => { + self.check_op(ops::Coroutine( + self.tcx + .coroutine_kind(self.body.source.def_id()) + .expect("Only expected to have a yield in a coroutine"), + )); + } TerminatorKind::CoroutineDrop => { span_bug!( @@ -819,8 +882,19 @@ fn is_int_bool_float_or_char(ty: Ty<'_>) -> bool { ty.is_bool() || ty.is_integral() || ty.is_char() || ty.is_floating_point() } -fn emit_unstable_in_stable_error(ccx: &ConstCx<'_, '_>, span: Span, gate: Symbol) { +fn emit_unstable_in_stable_exposed_error( + ccx: &ConstCx<'_, '_>, + span: Span, + gate: Symbol, + is_function_call: bool, +) -> ErrorGuaranteed { let attr_span = ccx.tcx.def_span(ccx.def_id()).shrink_to_lo(); - ccx.dcx().emit_err(UnstableInStable { gate: gate.to_string(), span, attr_span }); + ccx.dcx().emit_err(errors::UnstableInStableExposed { + gate: gate.to_string(), + span, + attr_span, + is_function_call, + is_function_call2: is_function_call, + }) } diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index 3720418d4f0..56da6791847 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -59,10 +59,12 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> { self.const_kind.expect("`const_kind` must not be called on a non-const fn") } - pub fn is_const_stable_const_fn(&self) -> bool { + 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`. self.const_kind == Some(hir::ConstContext::ConstFn) && self.tcx.features().staged_api() - && is_const_stable_const_fn(self.tcx, self.def_id().to_def_id()) + && is_safe_to_expose_on_stable_const_fn(self.tcx, self.def_id().to_def_id()) } fn is_async(&self) -> bool { @@ -90,50 +92,38 @@ pub fn rustc_allow_const_fn_unstable( attr::rustc_allow_const_fn_unstable(tcx.sess, attrs).any(|name| name == feature_gate) } -/// Returns `true` if the given `const fn` is "const-stable". +/// Returns `true` if the given `const fn` is "safe to expose on stable". /// /// Panics if the given `DefId` does not refer to a `const fn`. /// -/// Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable" -/// functions can be called in a const-context by users of the stable compiler. "const-stable" -/// functions are subject to more stringent restrictions than "const-unstable" functions: They -/// cannot use unstable features and can only call other "const-stable" functions. -pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - // A default body in a `#[const_trait]` is not const-stable because const - // trait fns currently cannot be const-stable. We shouldn't - // restrict default bodies to only call const-stable functions. +/// This is relevant within a `staged_api` crate. Unlike with normal features, the use of unstable +/// const features *recursively* taints the functions that use them. This is to avoid accidentally +/// exposing e.g. the implementation of an unstable const intrinsic on stable. So we partition the +/// world into two functions: those that are safe to expose on stable (and hence may not use +/// unstable features, not even recursively), and those that are not. +pub fn is_safe_to_expose_on_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + // A default body in a `#[const_trait]` is not const-stable because const trait fns currently + // cannot be const-stable. These functions can't be called from anything stable, so we shouldn't + // restrict them to only call const-stable functions. if tcx.is_const_default_method(def_id) { + // FIXME(const_trait_impl): we have to eventually allow some of these if these things can ever be stable. + // They should probably behave like regular `const fn` for that... return false; } // Const-stability is only relevant for `const fn`. - assert!(tcx.is_const_fn_raw(def_id)); + assert!(tcx.is_const_fn(def_id)); - // A function is only const-stable if it has `#[rustc_const_stable]` or it the trait it belongs - // to is const-stable. match tcx.lookup_const_stability(def_id) { - Some(stab) => stab.is_const_stable(), - None if is_parent_const_stable_trait(tcx, def_id) => { - // Remove this when `#![feature(const_trait_impl)]` is stabilized, - // returning `true` unconditionally. - tcx.dcx().span_delayed_bug( - tcx.def_span(def_id), - "trait implementations cannot be const stable yet", - ); - true + 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 + } + 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 } - None => false, // By default, items are not const stable. - } -} - -fn is_parent_const_stable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - let local_def_id = def_id.expect_local(); - let hir_id = tcx.local_def_id_to_hir_id(local_def_id); - - let parent_owner_id = tcx.parent_hir_id(hir_id).owner; - if !tcx.is_const_trait_impl_raw(parent_owner_id.to_def_id()) { - return false; } - - tcx.lookup_const_stability(parent_owner_id).is_some_and(|stab| stab.is_const_stable()) } diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 5c4a899f28a..3ac06ae6491 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -26,8 +26,16 @@ use crate::{errors, fluent_generated}; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Status { - Allowed, - Unstable(Symbol), + Unstable { + /// The feature that must be enabled to use this operation. + gate: Symbol, + /// Whether it is allowed to use this operation from stable `const fn`. + /// This will usually be `false`. + safe_to_expose_on_stable: bool, + /// We indicate whether this is a function call, since we can use targeted + /// diagnostics for "callee is not safe to expose om stable". + is_function_call: bool, + }, Forbidden, } @@ -40,9 +48,9 @@ pub enum DiagImportance { Secondary, } -/// An operation that is not *always* allowed in a const context. +/// An operation that is *not allowed* in a const context. pub trait NonConstOp<'tcx>: std::fmt::Debug { - /// Returns an enum indicating whether this operation is allowed within the given item. + /// Returns an enum indicating whether this operation can be enabled with a feature gate. fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { Status::Forbidden } @@ -114,7 +122,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { if let Ok(Some(ImplSource::UserDefined(data))) = implsrc { // FIXME(effects) revisit this - if !tcx.is_const_trait_impl_raw(data.impl_def_id) { + if !tcx.is_const_trait_impl(data.impl_def_id) { let span = tcx.def_span(data.impl_def_id); err.subdiagnostic(errors::NonConstImplNote { span }); } @@ -166,7 +174,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { let note = match self_ty.kind() { FnDef(def_id, ..) => { let span = tcx.def_span(*def_id); - if ccx.tcx.is_const_fn_raw(*def_id) { + if ccx.tcx.is_const_fn(*def_id) { span_bug!(span, "calling const FnDef errored when it shouldn't"); } @@ -298,30 +306,78 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { /// /// Contains the name of the feature that would allow the use of this function. #[derive(Debug)] -pub(crate) struct FnCallUnstable(pub DefId, pub Option<Symbol>); +pub(crate) struct FnCallUnstable { + pub def_id: DefId, + pub feature: Symbol, + pub safe_to_expose_on_stable: bool, +} impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - let FnCallUnstable(def_id, feature) = *self; - - let mut err = ccx - .dcx() - .create_err(errors::UnstableConstFn { span, def_path: ccx.tcx.def_path_str(def_id) }); + fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { + Status::Unstable { + gate: self.feature, + safe_to_expose_on_stable: self.safe_to_expose_on_stable, + is_function_call: true, + } + } + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { + let mut err = ccx.dcx().create_err(errors::UnstableConstFn { + span, + def_path: ccx.tcx.def_path_str(self.def_id), + }); // FIXME: make this translatable #[allow(rustc::untranslatable_diagnostic)] - if ccx.is_const_stable_const_fn() { - err.help(fluent_generated::const_eval_const_stable); - } else if ccx.tcx.sess.is_nightly_build() { - if let Some(feature) = feature { - err.help(format!("add `#![feature({feature})]` to the crate attributes to enable")); - } - } + err.help(format!("add `#![feature({})]` to the crate attributes to enable", self.feature)); err } } +/// A call to an intrinsic that is just not const-callable at all. +#[derive(Debug)] +pub(crate) struct IntrinsicNonConst { + pub name: Symbol, +} + +impl<'tcx> NonConstOp<'tcx> for IntrinsicNonConst { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { + ccx.dcx().create_err(errors::NonConstIntrinsic { + span, + name: self.name, + kind: ccx.const_kind(), + }) + } +} + +/// A call to an intrinsic that is just not const-callable at all. +#[derive(Debug)] +pub(crate) struct IntrinsicUnstable { + pub name: Symbol, + pub feature: Symbol, + pub const_stable_indirect: bool, +} + +impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable { + fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { + Status::Unstable { + gate: self.feature, + safe_to_expose_on_stable: self.const_stable_indirect, + // We do *not* want to suggest to mark the intrinsic as `const_stable_indirect`, + // that's not a trivial change! + is_function_call: false, + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { + ccx.dcx().create_err(errors::UnstableIntrinsic { + span, + name: self.name, + feature: self.feature, + }) + } +} + #[derive(Debug)] pub(crate) struct Coroutine(pub hir::CoroutineKind); impl<'tcx> NonConstOp<'tcx> for Coroutine { @@ -331,7 +387,11 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine { hir::CoroutineSource::Block, ) = self.0 { - Status::Unstable(sym::const_async_blocks) + Status::Unstable { + gate: sym::const_async_blocks, + safe_to_expose_on_stable: false, + is_function_call: false, + } } else { Status::Forbidden } diff --git a/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs index d04d7b273f0..0173a528c22 100644 --- a/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs @@ -15,7 +15,7 @@ use crate::check_consts::rustc_allow_const_fn_unstable; /// elaboration. pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool { // Const-stable functions must always use the stable live drop checker... - if ccx.is_const_stable_const_fn() { + if ccx.enforce_recursive_const_stability() { // ...except if they have the feature flag set via `rustc_allow_const_fn_unstable`. return rustc_allow_const_fn_unstable( ccx.tcx, diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index ca0993f0580..037fdcbcf9b 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -1,25 +1,8 @@ +use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_span::symbol::Symbol; -use {rustc_attr as attr, rustc_hir as hir}; - -/// Whether the `def_id` is an unstable const fn and what feature gate(s) are necessary to enable -/// it. -pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<(Symbol, Option<Symbol>)> { - if tcx.is_const_fn_raw(def_id) { - let const_stab = tcx.lookup_const_stability(def_id)?; - match const_stab.level { - attr::StabilityLevel::Unstable { implied_by, .. } => { - Some((const_stab.feature, implied_by)) - } - attr::StabilityLevel::Stable { .. } => None, - } - } else { - None - } -} pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { let parent_id = tcx.local_parent(def_id); diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 2db43a0f787..d54c5b750f0 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -219,7 +219,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { } /// "Intercept" a function call, because we have something special to do for it. - /// All `#[rustc_do_not_const_check]` functions should be hooked here. + /// All `#[rustc_do_not_const_check]` functions MUST be hooked here. /// If this returns `Some` function, which may be `instance` or a different function with /// compatible arguments, then evaluation should continue with that function. /// If this returns `None`, the function call has been handled and the function has returned. @@ -431,8 +431,8 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // sensitive check here. But we can at least rule out functions that are not const at // all. That said, we have to allow calling functions inside a trait marked with // #[const_trait]. These *are* const-checked! - // FIXME: why does `is_const_fn_raw` not classify them as const? - if (!ecx.tcx.is_const_fn_raw(def) && !ecx.tcx.is_const_default_method(def)) + // FIXME(effects): why does `is_const_fn` not classify them as const? + if (!ecx.tcx.is_const_fn(def) && !ecx.tcx.is_const_default_method(def)) || ecx.tcx.has_attr(def, sym::rustc_do_not_const_check) { // We certainly do *not* want to actually call the fn diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 211668cf055..38b87b72634 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -14,7 +14,7 @@ use rustc_middle::mir::interpret::{ UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, }; use rustc_middle::ty::{self, Mutability, Ty}; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use rustc_target::abi::WrappingRange; use rustc_target::abi::call::AdjustForForeignAbiError; @@ -44,11 +44,15 @@ pub(crate) struct MutablePtrInFinal { } #[derive(Diagnostic)] -#[diag(const_eval_unstable_in_stable)] -pub(crate) struct UnstableInStable { +#[diag(const_eval_unstable_in_stable_exposed)] +pub(crate) struct UnstableInStableExposed { pub gate: String, #[primary_span] pub span: Span, + #[help(const_eval_is_function_call)] + pub is_function_call: bool, + /// Need to duplicate the field so that fluent also provides it as a variable... + pub is_function_call2: bool, #[suggestion( const_eval_unstable_sugg, code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n", @@ -118,6 +122,34 @@ pub(crate) struct UnstableConstFn { } #[derive(Diagnostic)] +#[diag(const_eval_unstable_intrinsic)] +#[help] +pub(crate) struct UnstableIntrinsic { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub feature: Symbol, +} + +#[derive(Diagnostic)] +#[diag(const_eval_unmarked_const_fn_exposed)] +#[help] +pub(crate) struct UnmarkedConstFnExposed { + #[primary_span] + pub span: Span, + pub def_path: String, +} + +#[derive(Diagnostic)] +#[diag(const_eval_unmarked_intrinsic_exposed)] +#[help] +pub(crate) struct UnmarkedIntrinsicExposed { + #[primary_span] + pub span: Span, + pub def_path: String, +} + +#[derive(Diagnostic)] #[diag(const_eval_mutable_ref_escaping, code = E0764)] pub(crate) struct MutableRefEscaping { #[primary_span] @@ -154,6 +186,15 @@ pub(crate) struct NonConstFnCall { } #[derive(Diagnostic)] +#[diag(const_eval_non_const_intrinsic)] +pub(crate) struct NonConstIntrinsic { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub kind: ConstContext, +} + +#[derive(Diagnostic)] #[diag(const_eval_unallowed_op_in_const_context)] pub(crate) struct UnallowedOpInConstContext { #[primary_span] diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index bed500c3032..7e4bc508e5c 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -866,7 +866,9 @@ impl SyntaxExtension { }) .unwrap_or_else(|| (None, helper_attrs)); let stability = attr::find_stability(sess, attrs, span); - let const_stability = attr::find_const_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 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_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 5bd9e2fbcb9..dc6aa110f45 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -11,8 +11,8 @@ use rustc_ast::{ use rustc_attr as attr; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_feature::{ - ACCEPTED_LANG_FEATURES, AttributeSafety, Features, REMOVED_LANG_FEATURES, - UNSTABLE_LANG_FEATURES, + ACCEPTED_LANG_FEATURES, AttributeSafety, EnabledLangFeature, EnabledLibFeature, Features, + REMOVED_LANG_FEATURES, UNSTABLE_LANG_FEATURES, }; use rustc_lint_defs::BuiltinLintDiag; use rustc_parse::validate_attr; @@ -88,8 +88,11 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - // If the enabled feature is stable, record it. if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| name == f.name) { - let since = Some(Symbol::intern(f.since)); - features.set_enabled_lang_feature(name, mi.span(), since); + features.set_enabled_lang_feature(EnabledLangFeature { + gate_name: name, + attr_sp: mi.span(), + stable_since: Some(Symbol::intern(f.since)), + }); continue; } @@ -115,13 +118,19 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - { sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed); } - features.set_enabled_lang_feature(name, mi.span(), None); + + features.set_enabled_lang_feature(EnabledLangFeature { + gate_name: name, + attr_sp: mi.span(), + stable_since: None, + }); continue; } // Otherwise, the feature is unknown. Enable it as a lib feature. // It will be checked later whether the feature really exists. - features.set_enabled_lib_feature(name, mi.span()); + features + .set_enabled_lib_feature(EnabledLibFeature { gate_name: name, attr_sp: mi.span() }); // Similar to above, detect internal lib features to suppress // the ICE message that asks for a report. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 5921fbc0fd7..0069b07ad62 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -618,11 +618,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "allow_internal_unstable side-steps feature gating and stability checks", ), gated!( - rustc_allow_const_fn_unstable, Normal, - template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, EncodeCrossCrate::No, - "rustc_allow_const_fn_unstable side-steps feature gating and stability checks" - ), - gated!( allow_internal_unsafe, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, "allow_internal_unsafe side-steps the unsafe_code lint", ), @@ -838,6 +833,15 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_const_panic_str, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE ), + rustc_attr!( + rustc_const_stable_indirect, Normal, + template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL, + ), + gated!( + rustc_allow_const_fn_unstable, Normal, + template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, EncodeCrossCrate::No, + "rustc_allow_const_fn_unstable side-steps feature gating and stability checks" + ), // ========================================================================== // Internal attributes, Layout related: diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 216793485e5..9f42d3ec45c 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -135,4 +135,6 @@ pub use builtin_attrs::{ is_valid_for_get_attr, }; pub use removed::REMOVED_LANG_FEATURES; -pub use unstable::{Features, INCOMPATIBLE_FEATURES, UNSTABLE_LANG_FEATURES}; +pub use unstable::{ + EnabledLangFeature, EnabledLibFeature, Features, INCOMPATIBLE_FEATURES, UNSTABLE_LANG_FEATURES, +}; diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 39db0b31f9a..a81058e6ea1 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -36,35 +36,54 @@ macro_rules! status_to_enum { #[derive(Clone, Default, Debug)] pub struct Features { /// `#![feature]` attrs for language features, for error reporting. - enabled_lang_features: Vec<(Symbol, Span, Option<Symbol>)>, + enabled_lang_features: Vec<EnabledLangFeature>, /// `#![feature]` attrs for non-language (library) features. - enabled_lib_features: Vec<(Symbol, Span)>, + enabled_lib_features: Vec<EnabledLibFeature>, /// `enabled_lang_features` + `enabled_lib_features`. enabled_features: FxHashSet<Symbol>, } +/// Information about an enabled language feature. +#[derive(Debug, Copy, Clone)] +pub struct EnabledLangFeature { + /// Name of the feature gate guarding the language feature. + pub gate_name: Symbol, + /// Span of the `#[feature(...)]` attribute. + pub attr_sp: Span, + /// If the lang feature is stable, the version number when it was stabilized. + pub stable_since: Option<Symbol>, +} + +/// Information abhout an enabled library feature. +#[derive(Debug, Copy, Clone)] +pub struct EnabledLibFeature { + pub gate_name: Symbol, + pub attr_sp: Span, +} + impl Features { /// `since` should be set for stable features that are nevertheless enabled with a `#[feature]` /// attribute, indicating since when they are stable. - pub fn set_enabled_lang_feature(&mut self, name: Symbol, span: Span, since: Option<Symbol>) { - self.enabled_lang_features.push((name, span, since)); - self.enabled_features.insert(name); + pub fn set_enabled_lang_feature(&mut self, lang_feat: EnabledLangFeature) { + self.enabled_lang_features.push(lang_feat); + self.enabled_features.insert(lang_feat.gate_name); } - pub fn set_enabled_lib_feature(&mut self, name: Symbol, span: Span) { - self.enabled_lib_features.push((name, span)); - self.enabled_features.insert(name); + pub fn set_enabled_lib_feature(&mut self, lib_feat: EnabledLibFeature) { + self.enabled_lib_features.push(lib_feat); + self.enabled_features.insert(lib_feat.gate_name); } - /// Returns a list of triples with: - /// - feature gate name - /// - the span of the `#[feature]` attribute - /// - (for already stable features) the version since which it is stable - pub fn enabled_lang_features(&self) -> &Vec<(Symbol, Span, Option<Symbol>)> { + /// Returns a list of [`EnabledLangFeature`] with info about: + /// + /// - Feature gate name. + /// - The span of the `#[feature]` attribute. + /// - For stable language features, version info for when it was stabilized. + pub fn enabled_lang_features(&self) -> &Vec<EnabledLangFeature> { &self.enabled_lang_features } - pub fn enabled_lib_features(&self) -> &Vec<(Symbol, Span)> { + pub fn enabled_lib_features(&self) -> &Vec<EnabledLibFeature> { &self.enabled_lib_features } diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index 1121ca53240..09ddc6ca9de 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -1,7 +1,6 @@ //! Bounds are restrictions applied to some types after they've been lowered from the HIR to the //! [`rustc_middle::ty`] form. -use rustc_data_structures::fx::FxIndexMap; use rustc_hir::LangItem; use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; use rustc_span::Span; @@ -25,7 +24,6 @@ use rustc_span::Span; #[derive(Default, PartialEq, Eq, Clone, Debug)] pub(crate) struct Bounds<'tcx> { clauses: Vec<(ty::Clause<'tcx>, Span)>, - effects_min_tys: FxIndexMap<Ty<'tcx>, Span>, } impl<'tcx> Bounds<'tcx> { @@ -96,15 +94,7 @@ impl<'tcx> Bounds<'tcx> { } } - pub(crate) fn clauses( - &self, - // FIXME(effects): remove tcx - _tcx: TyCtxt<'tcx>, - ) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ { + pub(crate) fn clauses(&self) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ { self.clauses.iter().cloned() } - - pub(crate) fn effects_min_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_ { - self.effects_min_tys.keys().copied() - } } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index f46b7a8bc9c..3add801cf56 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1597,7 +1597,7 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai impl_.of_trait.as_ref().map(|ast_trait_ref| { let selfty = tcx.type_of(def_id).instantiate_identity(); - check_impl_constness(tcx, tcx.is_const_trait_impl_raw(def_id.to_def_id()), ast_trait_ref); + check_impl_constness(tcx, tcx.is_const_trait_impl(def_id.to_def_id()), ast_trait_ref); let trait_ref = icx.lowerer().lower_impl_trait_ref(ast_trait_ref, selfty); diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 075faea3d2a..b2ad42be6c7 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -67,7 +67,7 @@ fn associated_type_bounds<'tcx>( ) }); - let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(bounds_from_parent)); + let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent)); debug!( "associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id.to_def_id()), @@ -339,7 +339,7 @@ fn opaque_type_bounds<'tcx>( } debug!(?bounds); - tcx.arena.alloc_from_iter(bounds.clauses(tcx)) + tcx.arena.alloc_from_iter(bounds.clauses()) }) } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 61dc4b1677c..644ff0c667c 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -106,7 +106,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen return ty::GenericPredicates { parent: Some(tcx.parent(def_id.to_def_id())), predicates: tcx.arena.alloc_from_iter(predicates), - effects_min_tys: ty::List::empty(), }; } @@ -128,7 +127,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen return ty::GenericPredicates { parent: Some(impl_def_id), predicates: tcx.arena.alloc_from_iter(impl_predicates), - effects_min_tys: ty::List::empty(), }; } @@ -154,7 +152,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // We use an `IndexSet` to preserve order of insertion. // Preserving the order of insertion is important here so as not to break UI tests. let mut predicates: FxIndexSet<(ty::Clause<'_>, Span)> = FxIndexSet::default(); - let mut effects_min_tys = Vec::new(); let hir_generics = node.generics().unwrap_or(NO_GENERICS); if let Node::Item(item) = node { @@ -189,8 +186,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen ty::List::empty(), PredicateFilter::All, ); - predicates.extend(bounds.clauses(tcx)); - effects_min_tys.extend(bounds.effects_min_tys()); + predicates.extend(bounds.clauses()); } // In default impls, we can assume that the self type implements @@ -223,7 +219,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen param.span, ); trace!(?bounds); - predicates.extend(bounds.clauses(tcx)); + predicates.extend(bounds.clauses()); trace!(?predicates); } hir::GenericParamKind::Const { .. } => { @@ -275,8 +271,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen bound_vars, PredicateFilter::All, ); - predicates.extend(bounds.clauses(tcx)); - effects_min_tys.extend(bounds.effects_min_tys()); + predicates.extend(bounds.clauses()); } hir::WherePredicate::RegionPredicate(region_pred) => { @@ -348,7 +343,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen ty::GenericPredicates { parent: generics.parent, predicates: tcx.arena.alloc_from_iter(predicates), - effects_min_tys: tcx.mk_type_list(&effects_min_tys), } } @@ -499,7 +493,6 @@ pub(super) fn explicit_predicates_of<'tcx>( ty::GenericPredicates { parent: predicates_and_bounds.parent, predicates: tcx.arena.alloc_slice(&predicates), - effects_min_tys: predicates_and_bounds.effects_min_tys, } } } else { @@ -551,7 +544,6 @@ pub(super) fn explicit_predicates_of<'tcx>( return GenericPredicates { parent: parent_preds.parent, predicates: { tcx.arena.alloc_from_iter(filtered_predicates) }, - effects_min_tys: parent_preds.effects_min_tys, }; } gather_explicit_predicates_of(tcx, def_id) @@ -630,7 +622,7 @@ pub(super) fn implied_predicates_with_filter<'tcx>( // Combine the two lists to form the complete set of superbounds: let implied_bounds = - &*tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(where_bounds_that_match)); + &*tcx.arena.alloc_from_iter(bounds.clauses().chain(where_bounds_that_match)); debug!(?implied_bounds); // Now require that immediate supertraits are lowered, which will, in @@ -874,7 +866,7 @@ impl<'tcx> ItemCtxt<'tcx> { ); } - bounds.clauses(self.tcx).collect() + bounds.clauses().collect() } } @@ -966,7 +958,7 @@ pub(super) fn const_conditions<'tcx>( ty::ConstConditions { parent: has_parent.then(|| tcx.local_parent(def_id).to_def_id()), - predicates: tcx.arena.alloc_from_iter(bounds.clauses(tcx).map(|(clause, span)| { + predicates: tcx.arena.alloc_from_iter(bounds.clauses().map(|(clause, span)| { ( clause.kind().map_bound(|clause| match clause { ty::ClauseKind::HostEffect(ty::HostEffectPredicate { diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index 4d3595965c9..e65420ea8bf 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -278,8 +278,6 @@ impl<'tcx> PredicatesBuilder<'tcx> { ty::GenericPredicates { parent: self.parent, predicates: self.tcx.arena.alloc_from_iter(preds), - // FIXME(fn_delegation): Support effects. - effects_min_tys: ty::List::empty(), } } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index 3449270564a..890e8fa99e6 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -62,7 +62,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut trait_bounds = vec![]; let mut projection_bounds = vec![]; - for (pred, span) in bounds.clauses(tcx) { + for (pred, span) in bounds.clauses() { let bound_pred = pred.kind(); match bound_pred.skip_binder() { ty::ClauseKind::Trait(trait_pred) => { diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 190e405282c..ed56bb9c455 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -537,7 +537,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // This check is here because there is currently no way to express a trait bound for `FnDef` types only. if let ty::FnDef(def_id, _args) = *arg_ty.kind() { - if idx == 0 && !self.tcx.is_const_fn_raw(def_id) { + if idx == 0 && !self.tcx.is_const_fn(def_id) { self.dcx().emit_err(errors::ConstSelectMustBeConst { span }); } } else { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index da231acbb0f..92c2a906055 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1751,7 +1751,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // to tell them that in the diagnostic. Does not affect typeck. let is_constable = match element.kind { hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() { - ty::FnDef(def_id, _) if tcx.is_const_fn(def_id) => traits::IsConstable::Fn, + ty::FnDef(def_id, _) if tcx.is_stable_const_fn(def_id) => traits::IsConstable::Fn, _ => traits::IsConstable::No, }, hir::ExprKind::Path(qpath) => { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index a1e4bc75c21..70d51c92750 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1894,11 +1894,11 @@ impl EarlyLintPass for KeywordIdents { fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) { self.check_tokens(cx, &mac.args.tokens); } - fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) { + fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: &Ident) { if ident.name.as_str().starts_with('\'') { self.check_ident_token(cx, UnderMacro(false), ident.without_first_quote(), "'"); } else { - self.check_ident_token(cx, UnderMacro(false), ident, ""); + self.check_ident_token(cx, UnderMacro(false), *ident, ""); } } } @@ -2289,13 +2289,15 @@ declare_lint_pass!( impl EarlyLintPass for IncompleteInternalFeatures { fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) { let features = cx.builder.features(); - features - .enabled_lang_features() - .iter() - .map(|(name, span, _)| (name, span)) - .chain(features.enabled_lib_features().iter().map(|(name, span)| (name, span))) - .filter(|(&name, _)| features.incomplete(name) || features.internal(name)) - .for_each(|(&name, &span)| { + let lang_features = + features.enabled_lang_features().iter().map(|feat| (feat.gate_name, feat.attr_sp)); + let lib_features = + features.enabled_lib_features().iter().map(|feat| (feat.gate_name, feat.attr_sp)); + + lang_features + .chain(lib_features) + .filter(|(name, _)| features.incomplete(*name) || features.internal(*name)) + .for_each(|(name, span)| { if features.incomplete(name) { let note = rustc_feature::find_feature_issue(name, GateIssue::Language) .map(|n| BuiltinFeatureIssueNote { n }); diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index c095199a471..a6210aa520f 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -202,7 +202,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> ast_visit::walk_ty(self, t); } - fn visit_ident(&mut self, ident: Ident) { + fn visit_ident(&mut self, ident: &Ident) { lint_callback!(self, check_ident, ident); } diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index a1d436e0d3d..75ae994a86b 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -133,7 +133,7 @@ macro_rules! early_lint_methods { ($macro:path, $args:tt) => ( $macro!($args, [ fn check_param(a: &rustc_ast::Param); - fn check_ident(a: rustc_span::symbol::Ident); + fn check_ident(a: &rustc_span::symbol::Ident); fn check_crate(a: &rustc_ast::Crate); fn check_crate_post(a: &rustc_ast::Crate); fn check_item(a: &rustc_ast::Item); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index f196d58c22d..a4c49a15905 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -16,7 +16,6 @@ declare_lint_pass! { /// that are used by other parts of the compiler. HardwiredLints => [ // tidy-alphabetical-start - ABI_UNSUPPORTED_VECTOR_TYPES, ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_ASSOCIATED_ITEMS, AMBIGUOUS_GLOB_IMPORTS, @@ -5029,69 +5028,3 @@ declare_lint! { }; crate_level_only } - -declare_lint! { - /// The `abi_unsupported_vector_types` lint detects function definitions and calls - /// whose ABI depends on enabling certain target features, but those features are not enabled. - /// - /// ### Example - /// - /// ```rust,ignore (fails on non-x86_64) - /// extern "C" fn missing_target_feature(_: std::arch::x86_64::__m256) { - /// todo!() - /// } - /// - /// #[target_feature(enable = "avx")] - /// unsafe extern "C" fn with_target_feature(_: std::arch::x86_64::__m256) { - /// todo!() - /// } - /// - /// fn main() { - /// let v = unsafe { std::mem::zeroed() }; - /// unsafe { with_target_feature(v); } - /// } - /// ``` - /// - /// ```text - /// warning: ABI error: this function call uses a avx vector type, which is not enabled in the caller - /// --> lint_example.rs:18:12 - /// | - /// | unsafe { with_target_feature(v); } - /// | ^^^^^^^^^^^^^^^^^^^^^^ function called here - /// | - /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - /// = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> - /// = help: consider enabling it globally (-C target-feature=+avx) or locally (#[target_feature(enable="avx")]) - /// = note: `#[warn(abi_unsupported_vector_types)]` on by default - /// - /// - /// warning: ABI error: this function definition uses a avx vector type, which is not enabled - /// --> lint_example.rs:3:1 - /// | - /// | pub extern "C" fn with_target_feature(_: std::arch::x86_64::__m256) { - /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here - /// | - /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - /// = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> - /// = help: consider enabling it globally (-C target-feature=+avx) or locally (#[target_feature(enable="avx")]) - /// ``` - /// - /// - /// - /// ### Explanation - /// - /// The C ABI for `__m256` requires the value to be passed in an AVX register, - /// which is only possible when the `avx` target feature is enabled. - /// Therefore, `missing_target_feature` cannot be compiled without that target feature. - /// A similar (but complementary) message is triggered when `with_target_feature` is called - /// by a function that does not enable the `avx` target feature. - /// - /// Note that this lint is very similar to the `-Wpsabi` warning in `gcc`/`clang`. - pub ABI_UNSUPPORTED_VECTOR_TYPES, - Warn, - "this function call or definition uses a vector type which is not enabled", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, - reference: "issue #116558 <https://github.com/rust-lang/rust/issues/116558>", - }; -} diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index e06c86ae4c0..47f7a8b7c20 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1081,7 +1081,7 @@ fn should_encode_mir( && (generics.requires_monomorphization(tcx) || tcx.cross_crate_inlinable(def_id))); // The function has a `const` modifier or is in a `#[const_trait]`. - let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id()) + let is_const_fn = tcx.is_const_fn(def_id.to_def_id()) || tcx.is_const_default_method(def_id.to_def_id()); (is_const_fn, opt) } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 8fd5ff1f369..926691013dd 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -329,7 +329,7 @@ impl<'hir> Map<'hir> { BodyOwnerKind::Static(mutability) => ConstContext::Static(mutability), BodyOwnerKind::Fn if self.tcx.is_constructor(def_id) => return None, - BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.tcx.is_const_fn_raw(def_id) => { + BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.tcx.is_const_fn(def_id) => { ConstContext::ConstFn } BodyOwnerKind::Fn if self.tcx.is_const_default_method(def_id) => ConstContext::ConstFn, diff --git a/compiler/rustc_middle/src/mir/graphviz.rs b/compiler/rustc_middle/src/mir/graphviz.rs index a3fe8f9cffa..7bb41193d5c 100644 --- a/compiler/rustc_middle/src/mir/graphviz.rs +++ b/compiler/rustc_middle/src/mir/graphviz.rs @@ -17,7 +17,7 @@ where let mirs = def_ids .iter() .flat_map(|def_id| { - if tcx.is_const_fn_raw(*def_id) { + if tcx.is_const_fn(*def_id) { vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)] } else { vec![tcx.instance_mir(ty::InstanceKind::Item(*def_id))] diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 56ca9167d4d..d8d99deeb2c 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -86,11 +86,9 @@ impl<'tcx> MonoItem<'tcx> { } } - pub fn is_generic_fn(&self, tcx: TyCtxt<'tcx>) -> bool { + pub fn is_generic_fn(&self) -> bool { match self { - MonoItem::Fn(instance) => { - instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some() - } + MonoItem::Fn(instance) => instance.args.non_erasable_generics().next().is_some(), MonoItem::Static(..) | MonoItem::GlobalAsm(..) => false, } } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index faa022b50ef..e690bf74b6b 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -317,7 +317,7 @@ pub fn write_mir_pretty<'tcx>( }; // For `const fn` we want to render both the optimized MIR and the MIR for ctfe. - if tcx.is_const_fn_raw(def_id) { + if tcx.is_const_fn(def_id) { render_body(w, tcx.optimized_mir(def_id))?; writeln!(w)?; writeln!(w, "// MIR FOR CTFE")?; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d03fc39c9ad..94bdb913528 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -741,12 +741,11 @@ rustc_queries! { desc { |tcx| "computing drop-check constraints for `{}`", tcx.def_path_str(key) } } - /// Returns `true` if this is a const fn, use the `is_const_fn` to know whether your crate - /// actually sees it as const fn (e.g., the const-fn-ness might be unstable and you might - /// not have the feature gate active). + /// Returns `true` if this is a const fn / const impl. /// /// **Do not call this function manually.** It is only meant to cache the base data for the - /// `is_const_fn` function. Consider using `is_const_fn` or `is_const_fn_raw` instead. + /// higher-level functions. Consider using `is_const_fn` or `is_const_trait_impl` instead. + /// Also note that neither of them takes into account feature gates and stability. query constness(key: DefId) -> hir::Constness { desc { |tcx| "checking if item is const: `{}`", tcx.def_path_str(key) } separate_provide_extern diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index eab106a4403..a6a0a6dc222 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3120,39 +3120,24 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// Whether the `def_id` counts as const fn in the current crate, considering all active - /// feature gates - pub fn is_const_fn(self, def_id: DefId) -> bool { - if self.is_const_fn_raw(def_id) { - match self.lookup_const_stability(def_id) { - Some(stability) if stability.is_const_unstable() => { - // has a `rustc_const_unstable` attribute, check whether the user enabled the - // corresponding feature gate. - self.features().enabled(stability.feature) - } - // functions without const stability are either stable user written - // const fn or the user is using feature gates and we thus don't - // care what they do - _ => true, + /// Whether `def_id` is a stable const fn (i.e., doesn't need any feature gates to be called). + /// + /// When this is `false`, the function may still be callable as a `const fn` due to features + /// being enabled! + pub fn is_stable_const_fn(self, def_id: DefId) -> bool { + self.is_const_fn(def_id) + && match self.lookup_const_stability(def_id) { + None => true, // a fn in a non-staged_api crate + Some(stability) if stability.is_const_stable() => true, + _ => false, } - } else { - false - } } // FIXME(effects): Please remove this. It's a footgun. /// Whether the trait impl is marked const. This does not consider stability or feature gates. - pub fn is_const_trait_impl_raw(self, def_id: DefId) -> bool { - let Some(local_def_id) = def_id.as_local() else { return false }; - let node = self.hir_node_by_def_id(local_def_id); - - matches!( - node, - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { constness, .. }), - .. - }) if matches!(constness, hir::Constness::Const) - ) + pub fn is_const_trait_impl(self, def_id: DefId) -> bool { + self.def_kind(def_id) == DefKind::Impl { of_trait: true } + && self.constness(def_id) == hir::Constness::Const } pub fn intrinsic(self, def_id: impl IntoQueryParam<DefId> + Copy) -> Option<ty::IntrinsicDef> { diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 64405d18c7d..84f52bfe48f 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -70,7 +70,7 @@ impl<'tcx> Ty<'tcx> { /// ADTs with no type arguments. pub fn is_simple_text(self, tcx: TyCtxt<'tcx>) -> bool { match self.kind() { - Adt(def, args) => args.non_erasable_generics(tcx, def.did()).next().is_none(), + Adt(_, args) => args.non_erasable_generics().next().is_none(), Ref(_, ty, _) => ty.is_simple_text(tcx), _ => self.is_simple_ty(), } diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 56111ee063e..737f1362b34 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -501,9 +501,6 @@ impl<'tcx> GenericArgs<'tcx> { #[inline] pub fn non_erasable_generics( &'tcx self, - // FIXME(effects): Remove these - _tcx: TyCtxt<'tcx>, - _def_id: DefId, ) -> impl DoubleEndedIterator<Item = GenericArgKind<'tcx>> + 'tcx { self.iter().filter_map(|k| match k.unpack() { ty::GenericArgKind::Lifetime(_) => None, diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index ab1b8fa6a73..19779740227 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -360,7 +360,6 @@ impl<'tcx> Generics { pub struct GenericPredicates<'tcx> { pub parent: Option<DefId>, pub predicates: &'tcx [(Clause<'tcx>, Span)], - pub effects_min_tys: &'tcx ty::List<Ty<'tcx>>, } impl<'tcx> GenericPredicates<'tcx> { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 61cb4322501..e237d382900 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -204,7 +204,7 @@ impl<'tcx> Instance<'tcx> { } // If this a non-generic instance, it cannot be a shared monomorphization. - self.args.non_erasable_generics(tcx, self.def_id()).next()?; + self.args.non_erasable_generics().next()?; // compiler_builtins cannot use upstream monomorphizations. if tcx.is_compiler_builtins(LOCAL_CRATE) { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 85414764817..b92fc864b49 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1995,8 +1995,11 @@ impl<'tcx> TyCtxt<'tcx> { (ident, scope) } + /// Checks whether this is a `const fn`. Returns `false` for non-functions. + /// + /// Even if this returns `true`, constness may still be unstable! #[inline] - pub fn is_const_fn_raw(self, def_id: DefId) -> bool { + pub fn is_const_fn(self, def_id: DefId) -> bool { matches!( self.def_kind(def_id), DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Closure diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index c9f24764cc2..42d6bdf6cee 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -439,12 +439,7 @@ impl<'tcx> Inliner<'tcx> { // Reachability pass defines which functions are eligible for inlining. Generally inlining // other functions is incorrect because they could reference symbols that aren't exported. - let is_generic = callsite - .callee - .args - .non_erasable_generics(self.tcx, callsite.callee.def_id()) - .next() - .is_some(); + let is_generic = callsite.callee.args.non_erasable_generics().next().is_some(); if !is_generic && !cross_crate_inlinable { return Err("not exported"); } diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 86c4b241a2b..fa9a6bfcf7c 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -673,7 +673,7 @@ impl<'tcx> Validator<'_, 'tcx> { } // Make sure the callee is a `const fn`. let is_const_fn = match *fn_ty.kind() { - ty::FnDef(def_id, _) => self.tcx.is_const_fn_raw(def_id), + ty::FnDef(def_id, _) => self.tcx.is_const_fn(def_id), _ => false, }; if !is_const_fn { diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index 6da387bbebc..7210701d482 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -1,12 +1,3 @@ -monomorphize_abi_error_disabled_vector_type_call = - ABI error: this function call uses a vector type that requires the `{$required_feature}` target feature, which is not enabled in the caller - .label = function called here - .help = consider enabling it globally (`-C target-feature=+{$required_feature}`) or locally (`#[target_feature(enable="{$required_feature}")]`) -monomorphize_abi_error_disabled_vector_type_def = - ABI error: this function definition uses a vector type that requires the `{$required_feature}` target feature, which is not enabled - .label = function defined here - .help = consider enabling it globally (`-C target-feature=+{$required_feature}`) or locally (`#[target_feature(enable="{$required_feature}")]`) - monomorphize_couldnt_dump_mono_stats = unexpected error occurred while dumping monomorphization stats: {$error} diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 3f9a0df0301..8df6e63deeb 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -205,7 +205,6 @@ //! this is not implemented however: a mono item will be produced //! regardless of whether it is actually needed or not. -mod abi_check; mod move_check; use std::path::PathBuf; @@ -505,7 +504,7 @@ fn collect_items_rec<'tcx>( // Check for PMEs and emit a diagnostic if one happened. To try to show relevant edges of the // mono item graph. if tcx.dcx().err_count() > error_count - && starting_item.node.is_generic_fn(tcx) + && starting_item.node.is_generic_fn() && starting_item.node.is_user_defined() { let formatted_item = with_no_trimmed_paths!(starting_item.node.to_string()); @@ -767,7 +766,6 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { self.used_mentioned_items.insert(MentionedItem::Fn(callee_ty)); let callee_ty = self.monomorphize(callee_ty); self.check_fn_args_move_size(callee_ty, args, *fn_span, location); - abi_check::check_call_site_abi(tcx, callee_ty, *fn_span, self.body.source.instance); visit_fn_use(self.tcx, callee_ty, true, source, &mut self.used_items) } mir::TerminatorKind::Drop { ref place, .. } => { @@ -1209,9 +1207,6 @@ fn collect_items_of_instance<'tcx>( mentioned_items: &mut MonoItems<'tcx>, mode: CollectionMode, ) { - // Check the instance for feature-dependent ABI. - abi_check::check_instance_abi(tcx, instance); - let body = tcx.instance_mir(instance.def); // Naively, in "used" collection mode, all functions get added to *both* `used_items` and // `mentioned_items`. Mentioned items processing will then notice that they have already been diff --git a/compiler/rustc_monomorphize/src/collector/abi_check.rs b/compiler/rustc_monomorphize/src/collector/abi_check.rs deleted file mode 100644 index 6b825019f20..00000000000 --- a/compiler/rustc_monomorphize/src/collector/abi_check.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! This module ensures that if a function's ABI requires a particular target feature, -//! that target feature is enabled both on the callee and all callers. -use rustc_hir::CRATE_HIR_ID; -use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt}; -use rustc_session::lint::builtin::ABI_UNSUPPORTED_VECTOR_TYPES; -use rustc_span::def_id::DefId; -use rustc_span::{Span, Symbol}; -use rustc_target::abi::call::{FnAbi, PassMode}; -use rustc_target::abi::{Abi, RegKind}; - -use crate::errors::{AbiErrorDisabledVectorTypeCall, AbiErrorDisabledVectorTypeDef}; - -fn uses_vector_registers(mode: &PassMode, abi: &Abi) -> bool { - match mode { - PassMode::Ignore | PassMode::Indirect { .. } => false, - PassMode::Cast { pad_i32: _, cast } => { - cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector)) - || cast.rest.unit.kind == RegKind::Vector - } - PassMode::Direct(..) | PassMode::Pair(..) => matches!(abi, Abi::Vector { .. }), - } -} - -fn do_check_abi<'tcx>( - tcx: TyCtxt<'tcx>, - abi: &FnAbi<'tcx, Ty<'tcx>>, - target_feature_def: DefId, - emit_err: impl Fn(&'static str), -) { - let Some(feature_def) = tcx.sess.target.features_for_correct_vector_abi() else { - return; - }; - let codegen_attrs = tcx.codegen_fn_attrs(target_feature_def); - for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) { - let size = arg_abi.layout.size; - if uses_vector_registers(&arg_abi.mode, &arg_abi.layout.abi) { - // Find the first feature that provides at least this vector size. - let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) { - Some((_, feature)) => feature, - None => { - emit_err("<no available feature for this size>"); - continue; - } - }; - let feature_sym = Symbol::intern(feature); - if !tcx.sess.unstable_target_features.contains(&feature_sym) - && !codegen_attrs.target_features.iter().any(|x| x.name == feature_sym) - { - emit_err(feature); - } - } - } -} - -/// Checks that the ABI of a given instance of a function does not contain vector-passed arguments -/// or return values for which the corresponding target feature is not enabled. -pub(super) fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { - let param_env = ParamEnv::reveal_all(); - let Ok(abi) = tcx.fn_abi_of_instance(param_env.and((instance, ty::List::empty()))) else { - // An error will be reported during codegen if we cannot determine the ABI of this - // function. - return; - }; - do_check_abi(tcx, abi, instance.def_id(), |required_feature| { - let span = tcx.def_span(instance.def_id()); - tcx.emit_node_span_lint( - ABI_UNSUPPORTED_VECTOR_TYPES, - CRATE_HIR_ID, - span, - AbiErrorDisabledVectorTypeDef { span, required_feature }, - ); - }) -} - -/// Checks that a call expression does not try to pass a vector-passed argument which requires a -/// target feature that the caller does not have, as doing so causes UB because of ABI mismatch. -pub(super) fn check_call_site_abi<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - span: Span, - caller: InstanceKind<'tcx>, -) { - let param_env = ParamEnv::reveal_all(); - let callee_abi = match *ty.kind() { - ty::FnPtr(..) => tcx.fn_abi_of_fn_ptr(param_env.and((ty.fn_sig(tcx), ty::List::empty()))), - ty::FnDef(def_id, args) => { - // Intrinsics are handled separately by the compiler. - if tcx.intrinsic(def_id).is_some() { - return; - } - let instance = ty::Instance::expect_resolve(tcx, param_env, def_id, args, span); - tcx.fn_abi_of_instance(param_env.and((instance, ty::List::empty()))) - } - _ => { - panic!("Invalid function call"); - } - }; - - let Ok(callee_abi) = callee_abi else { - // ABI failed to compute; this will not get through codegen. - return; - }; - do_check_abi(tcx, callee_abi, caller.def_id(), |required_feature| { - tcx.emit_node_span_lint( - ABI_UNSUPPORTED_VECTOR_TYPES, - CRATE_HIR_ID, - span, - AbiErrorDisabledVectorTypeCall { span, required_feature }, - ); - }) -} diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index 5048a8d5d99..d5fae6e23cb 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -92,21 +92,3 @@ pub(crate) struct StartNotFound; pub(crate) struct UnknownCguCollectionMode<'a> { pub mode: &'a str, } - -#[derive(LintDiagnostic)] -#[diag(monomorphize_abi_error_disabled_vector_type_def)] -#[help] -pub(crate) struct AbiErrorDisabledVectorTypeDef<'a> { - #[label] - pub span: Span, - pub required_feature: &'a str, -} - -#[derive(LintDiagnostic)] -#[diag(monomorphize_abi_error_disabled_vector_type_call)] -#[help] -pub(crate) struct AbiErrorDisabledVectorTypeCall<'a> { - #[label] - pub span: Span, - pub required_feature: &'a str, -} diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 9bf7e67417e..e2a6d392ca0 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -229,7 +229,7 @@ where } let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item); - let is_volatile = is_incremental_build && mono_item.is_generic_fn(cx.tcx); + let is_volatile = is_incremental_build && mono_item.is_generic_fn(); let cgu_name = match characteristic_def_id { Some(def_id) => compute_codegen_unit_name( @@ -822,7 +822,7 @@ fn mono_item_visibility<'tcx>( return Visibility::Hidden; } - let is_generic = instance.args.non_erasable_generics(tcx, def_id).next().is_some(); + let is_generic = instance.args.non_erasable_generics().next().is_some(); // Upstream `DefId` instances get different handling than local ones. let Some(def_id) = def_id.as_local() else { diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 3f98236595b..f8ef423a9b0 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -99,6 +99,10 @@ passes_collapse_debuginfo = passes_confusables = attribute should be applied to an inherent method .label = not an inherent method +passes_const_stable_not_stable = + attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]` + .label = attribute specified here + passes_continue_labeled_block = `continue` pointing to a labeled block .label = labeled blocks cannot be `continue`'d @@ -465,10 +469,10 @@ passes_may_dangle = `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl passes_maybe_string_interpolation = you might have meant to use string interpolation in this string literal + passes_missing_const_err = - attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` + attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` .help = make the function or method const - .label = attribute specified here passes_missing_const_stab_attr = {$descr} has missing const stability attribute diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 62c502f9524..ed0d7ed8acc 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1997,7 +1997,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ) { match target { Target::Fn | Target::Method(_) - if self.tcx.is_const_fn_raw(hir_id.expect_owner().to_def_id()) => {} + if self.tcx.is_const_fn(hir_id.expect_owner().to_def_id()) => {} // FIXME(#80564): We permit struct fields and match arms to have an // `#[allow_internal_unstable]` attribute with just a lint, because we previously // erroneously allowed it and some crates used it accidentally, to be compatible diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 042e50d890e..b5f1eac1cba 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1574,12 +1574,20 @@ pub(crate) struct DuplicateFeatureErr { pub span: Span, pub feature: Symbol, } + #[derive(Diagnostic)] #[diag(passes_missing_const_err)] pub(crate) struct MissingConstErr { #[primary_span] #[help] pub fn_sig_span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_const_stable_not_stable)] +pub(crate) struct ConstStableNotStable { + #[primary_span] + pub fn_sig_span: Span, #[label] pub const_span: Span, } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index a176b2bb1ad..466ea32735b 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -10,13 +10,13 @@ use rustc_attr::{ }; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; -use rustc_feature::ACCEPTED_LANG_FEATURES; +use rustc_feature::{ACCEPTED_LANG_FEATURES, EnabledLangFeature, EnabledLibFeature}; use rustc_hir as hir; 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::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant}; +use rustc_hir::{Constness, 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; @@ -27,7 +27,6 @@ use rustc_session::lint; use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED}; use rustc_span::Span; use rustc_span::symbol::{Symbol, sym}; -use rustc_target::spec::abi::Abi; use tracing::{debug, info}; use crate::errors; @@ -107,6 +106,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { def_id: LocalDefId, item_sp: Span, fn_sig: Option<&'tcx hir::FnSig<'tcx>>, + is_foreign_item: bool, kind: AnnotationKind, inherit_deprecation: InheritDeprecation, inherit_const_stability: InheritConstStability, @@ -163,30 +163,65 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } let stab = attr::find_stability(self.tcx.sess, attrs, item_sp); - let const_stab = attr::find_const_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); - let mut const_span = None; - let const_stab = const_stab.map(|(const_stab, const_span_node)| { - self.index.const_stab_map.insert(def_id, const_stab); - const_span = Some(const_span_node); - const_stab - }); - - // If the current node is a function, has const stability attributes and if it doesn not have an intrinsic ABI, - // check if the function/method is const or the parent impl block is const - if let (Some(const_span), Some(fn_sig)) = (const_span, fn_sig) - && fn_sig.header.abi != Abi::RustIntrinsic + // 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() - && (!self.in_trait_impl || !self.tcx.is_const_fn_raw(def_id.to_def_id())) + // We have to exclude foreign items as they might be intrinsics. Sadly we can't check + // their ABI; `fn_sig.abi` is *not* correct for foreign functions. + && !is_foreign_item + && const_stab.is_some() + && (!self.in_trait_impl || !self.tcx.is_const_fn(def_id.to_def_id())) + { + 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()) + // FIXME: we skip this check targets until + // <https://github.com/rust-lang/stdarch/pull/1654> propagates. + && false { self.tcx .dcx() - .emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span, const_span }); + .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(effects): 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 { @@ -247,6 +282,8 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } + // Stable *language* features shouldn't be used as unstable library features. + // (Not doing this for stable library features is checked by tidy.) if let Stability { level: Unstable { .. }, feature } = stab { if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() { self.tcx @@ -260,21 +297,13 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { self.index.implications.insert(implied_by, feature); } - if let Some(ConstStability { level: Unstable { .. }, feature, .. }) = const_stab { - if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() { - self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature { - span: const_span.unwrap(), // If const_stab contains Some(..), same is true for const_span - item_sp, - }); - } - } if let Some(ConstStability { level: Unstable { implied_by: Some(implied_by), .. }, feature, .. }) = const_stab { - self.index.implications.insert(implied_by, feature); + self.index.implications.insert(implied_by, feature.unwrap()); } self.index.stab_map.insert(def_id, stab); @@ -372,6 +401,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ctor_def_id, i.span, None, + /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -390,6 +420,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { i.owner_id.def_id, i.span, fn_sig, + /* is_foreign_item */ false, kind, InheritDeprecation::Yes, const_stab_inherit, @@ -409,6 +440,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ti.owner_id.def_id, ti.span, fn_sig, + /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -432,6 +464,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ii.owner_id.def_id, ii.span, fn_sig, + /* is_foreign_item */ false, kind, InheritDeprecation::Yes, InheritConstStability::No, @@ -447,6 +480,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { var.def_id, var.span, None, + /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -457,6 +491,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ctor_def_id, var.span, None, + /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -475,6 +510,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { s.def_id, s.span, None, + /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -486,10 +522,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { + let fn_sig = match &i.kind { + rustc_hir::ForeignItemKind::Fn(fn_sig, ..) => Some(fn_sig), + _ => None, + }; self.annotate( i.owner_id.def_id, i.span, - None, + fn_sig, + /* is_foreign_item */ true, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -512,6 +553,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { p.def_id, p.span, None, + /* is_foreign_item */ false, kind, InheritDeprecation::No, InheritConstStability::No, @@ -540,7 +582,9 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { } } - fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) { + 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; } @@ -554,10 +598,11 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { } let is_const = self.tcx.is_const_fn(def_id.to_def_id()) - || self.tcx.is_const_trait_impl_raw(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(); + 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 { let descr = self.tcx.def_descr(def_id.to_def_id()); @@ -587,7 +632,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } // Ensure stable `const fn` have a const stability attribute. - self.check_missing_const_stability(i.owner_id.def_id, i.span); + self.check_missing_or_wrong_const_stability(i.owner_id.def_id, i.span); intravisit::walk_item(self, i) } @@ -601,7 +646,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_const_stability(ii.owner_id.def_id, ii.span); + self.check_missing_or_wrong_const_stability(ii.owner_id.def_id, ii.span); } intravisit::walk_impl_item(self, ii); } @@ -670,6 +715,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID), None, + /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -732,12 +778,23 @@ 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 { of_trait: Some(ref t), self_ty, items, .. }) => { + hir::ItemKind::Impl(hir::Impl { + constness, + 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); + let const_stab = attr::find_const_stability( + self.tcx.sess, + attrs, + item.span, + matches!(constness, Constness::Const), + ); // If this impl block has an #[unstable] attribute, give an // error if all involved types and traits are stable, because @@ -763,7 +820,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { // `#![feature(const_trait_impl)]` is unstable, so any impl declared stable // needs to have an error emitted. if features.const_trait_impl() - && self.tcx.is_const_trait_impl_raw(item.owner_id.to_def_id()) + && self.tcx.is_const_trait_impl(item.owner_id.to_def_id()) && const_stab.is_some_and(|(stab, _)| stab.is_const_stable()) { self.tcx.dcx().emit_err(errors::TraitImplConstStable { span: item.span }); @@ -937,25 +994,25 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { let enabled_lang_features = tcx.features().enabled_lang_features(); let mut lang_features = UnordSet::default(); - for &(feature, span, since) in enabled_lang_features { - if let Some(since) = since { + for EnabledLangFeature { gate_name, attr_sp, stable_since } in enabled_lang_features { + if let Some(version) = stable_since { // Warn if the user has enabled an already-stable lang feature. - unnecessary_stable_feature_lint(tcx, span, feature, since); + unnecessary_stable_feature_lint(tcx, *attr_sp, *gate_name, *version); } - if !lang_features.insert(feature) { + if !lang_features.insert(gate_name) { // Warn if the user enables a lang feature multiple times. - tcx.dcx().emit_err(errors::DuplicateFeatureErr { span, feature }); + tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name }); } } let enabled_lib_features = tcx.features().enabled_lib_features(); let mut remaining_lib_features = FxIndexMap::default(); - for (feature, span) in enabled_lib_features { - if remaining_lib_features.contains_key(&feature) { + for EnabledLibFeature { gate_name, attr_sp } in enabled_lib_features { + if remaining_lib_features.contains_key(gate_name) { // Warn if the user enables a lib feature multiple times. - tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *span, feature: *feature }); + tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name }); } - remaining_lib_features.insert(feature, *span); + remaining_lib_features.insert(*gate_name, *attr_sp); } // `stdbuild` has special handling for `libc`, so we need to // recognise the feature when building std. @@ -987,7 +1044,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { /// time, less loading from metadata is performed and thus compiler performance is improved. fn check_features<'tcx>( tcx: TyCtxt<'tcx>, - remaining_lib_features: &mut FxIndexMap<&Symbol, Span>, + remaining_lib_features: &mut FxIndexMap<Symbol, Span>, remaining_implications: &mut UnordMap<Symbol, Symbol>, defined_features: &LibFeatures, all_implications: &UnordMap<Symbol, Symbol>, @@ -1057,7 +1114,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { } for (feature, span) in remaining_lib_features { - tcx.dcx().emit_err(errors::UnknownFeature { span, feature: *feature }); + tcx.dcx().emit_err(errors::UnknownFeature { span, feature }); } for (&implied_by, &feature) in remaining_implications.to_sorted_stable_ord() { diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs index 0665401df8e..5a72e80a0a5 100644 --- a/compiler/rustc_query_system/src/ich/impls_syntax.rs +++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs @@ -116,3 +116,20 @@ impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::Features { self.enabled_lib_features().hash_stable(hcx, hasher); } } + +impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::EnabledLangFeature { + fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { + let rustc_feature::EnabledLangFeature { gate_name, attr_sp, stable_since } = self; + gate_name.hash_stable(hcx, hasher); + attr_sp.hash_stable(hcx, hasher); + stable_since.hash_stable(hcx, hasher); + } +} + +impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::EnabledLibFeature { + fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { + let rustc_feature::EnabledLibFeature { gate_name, attr_sp } = self; + gate_name.hash_stable(hcx, hasher); + attr_sp.hash_stable(hcx, hasher); + } +} diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 0ca6bb8c07d..031ffaed808 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1321,7 +1321,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // Visit attributes after items for backward compatibility. // This way they can use `macro_rules` defined later. self.visit_vis(&item.vis); - self.visit_ident(item.ident); + self.visit_ident(&item.ident); item.kind.walk(item, AssocCtxt::Trait, self); visit::walk_list!(self, visit_attribute, &item.attrs); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 033cd7d5870..adb0ba7c820 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1205,7 +1205,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r } fn visit_assoc_item_constraint(&mut self, constraint: &'ast AssocItemConstraint) { - self.visit_ident(constraint.ident); + self.visit_ident(&constraint.ident); if let Some(ref gen_args) = constraint.gen_args { // Forbid anonymous lifetimes in GAT parameters until proper semantics are decided. self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { @@ -4582,7 +4582,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { fn resolve_expr_field(&mut self, f: &'ast ExprField, e: &'ast Expr) { self.resolve_expr(&f.expr, Some(e)); - self.visit_ident(f.ident); + self.visit_ident(&f.ident); walk_list!(self, visit_attribute, f.attrs.iter()); } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 8fa8f2ac402..9514ec883ae 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -161,8 +161,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates { let mut tables = self.0.borrow_mut(); let def_id = tables[def_id]; - let GenericPredicates { parent, predicates, effects_min_tys: _ } = - tables.tcx.predicates_of(def_id); + let GenericPredicates { parent, predicates } = tables.tcx.predicates_of(def_id); stable_mir::ty::GenericPredicates { parent: parent.map(|did| tables.trait_def(did)), predicates: predicates @@ -183,8 +182,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { ) -> stable_mir::ty::GenericPredicates { let mut tables = self.0.borrow_mut(); let def_id = tables[def_id]; - let GenericPredicates { parent, predicates, effects_min_tys: _ } = - tables.tcx.explicit_predicates_of(def_id); + let GenericPredicates { parent, predicates } = tables.tcx.explicit_predicates_of(def_id); stable_mir::ty::GenericPredicates { parent: parent.map(|did| tables.trait_def(did)), predicates: predicates diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index bf5f948fe91..134a1a1db30 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1660,6 +1660,7 @@ symbols! { rustc_confusables, rustc_const_panic_str, rustc_const_stable, + rustc_const_stable_indirect, rustc_const_unstable, rustc_conversion_suggestion, rustc_deallocator, diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 78e6b9ec6e8..5c5ab435dbd 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -135,7 +135,7 @@ fn symbol_name_provider<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty // This closure determines the instantiating crate for instances that // need an instantiating-crate-suffix for their symbol name, in order // to differentiate between local copies. - if is_generic(instance, tcx) { + if is_generic(instance) { // For generics we might find re-usable upstream instances. If there // is one, we rely on the symbol being instantiated locally. instance.upstream_monomorphization(tcx).unwrap_or(LOCAL_CRATE) @@ -241,7 +241,7 @@ fn compute_symbol_name<'tcx>( // the ID of the instantiating crate. This avoids symbol conflicts // in case the same instances is emitted in two crates of the same // project. - let avoid_cross_crate_conflicts = is_generic(instance, tcx) || is_globally_shared_function; + let avoid_cross_crate_conflicts = is_generic(instance) || is_globally_shared_function; let instantiating_crate = avoid_cross_crate_conflicts.then(compute_instantiating_crate); @@ -276,6 +276,6 @@ fn compute_symbol_name<'tcx>( symbol } -fn is_generic<'tcx>(instance: Instance<'tcx>, tcx: TyCtxt<'tcx>) -> bool { - instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some() +fn is_generic<'tcx>(instance: Instance<'tcx>) -> bool { + instance.args.non_erasable_generics().next().is_some() } diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 0d16c9a96aa..e92366d5c5c 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -522,13 +522,6 @@ pub fn all_known_features() -> impl Iterator<Item = (&'static str, Stability)> { .map(|(f, s, _)| (f, s)) } -// These arrays represent the least-constraining feature that is required for vector types up to a -// certain size to have their "proper" ABI on each architecture. -// Note that they must be kept sorted by vector size. -const X86_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = - &[(128, "sse"), (256, "avx"), (512, "avx512f")]; -const AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")]; - impl super::spec::Target { pub fn supported_target_features( &self, @@ -550,16 +543,6 @@ impl super::spec::Target { } } - // Returns None if we do not support ABI checks on the given target yet. - pub fn features_for_correct_vector_abi(&self) -> Option<&'static [(u64, &'static str)]> { - match &*self.arch { - "x86" | "x86_64" => Some(X86_FEATURES_FOR_CORRECT_VECTOR_ABI), - "aarch64" => Some(AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI), - // FIXME: add support for non-tier1 architectures - _ => None, - } - } - pub fn tied_target_features(&self) -> &'static [&'static [&'static str]] { match &*self.arch { "aarch64" | "arm64ec" => AARCH64_TIED_FEATURES, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 47601b0c18d..e027586563e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -393,7 +393,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let self_ty = obligation.self_ty().skip_binder(); match *self_ty.kind() { ty::Closure(def_id, _) => { - let is_const = self.tcx().is_const_fn_raw(def_id); + let is_const = self.tcx().is_const_fn(def_id); debug!(?kind, ?obligation, "assemble_unboxed_candidates"); match self.infcx.closure_kind(self_ty) { Some(closure_kind) => { @@ -413,7 +413,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::CoroutineClosure(def_id, args) => { let args = args.as_coroutine_closure(); - let is_const = self.tcx().is_const_fn_raw(def_id); + let is_const = self.tcx().is_const_fn(def_id); if let Some(closure_kind) = self.infcx.closure_kind(self_ty) // Ambiguity if upvars haven't been constrained yet && !args.tupled_upvars_ty().is_ty_var() diff --git a/library/alloc/src/collections/binary_heap/tests.rs b/library/alloc/src/collections/binary_heap/tests.rs index c18318724a4..ad0a020a1a9 100644 --- a/library/alloc/src/collections/binary_heap/tests.rs +++ b/library/alloc/src/collections/binary_heap/tests.rs @@ -350,7 +350,7 @@ fn test_drain_forget() { mem::forget(it); })) .unwrap(); - // Behaviour after leaking is explicitly unspecified and order is arbitrary, + // Behavior after leaking is explicitly unspecified and order is arbitrary, // so it's fine if these start failing, but probably worth knowing. assert!(q.is_empty()); assert_eq!(a.dropped() + b.dropped() + c.dropped(), 1); @@ -377,7 +377,7 @@ fn test_drain_sorted_forget() { mem::forget(it); })) .unwrap(); - // Behaviour after leaking is explicitly unspecified, + // Behavior after leaking is explicitly unspecified, // so it's fine if these start failing, but probably worth knowing. assert_eq!(q.len(), 2); assert_eq!(a.dropped(), 0); diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index d0e413778f8..db16d82be7d 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1216,7 +1216,7 @@ mod test_extract_if { { let mut it = map.extract_if(|dummy, _| dummy.query(true)); catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err(); - // Iterator behaviour after a panic is explicitly unspecified, + // Iterator behavior after a panic is explicitly unspecified, // so this is just the current implementation: let result = catch_unwind(AssertUnwindSafe(|| it.next())); assert!(matches!(result, Ok(None))); diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 45de0617f33..85a9120c7e2 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -103,7 +103,7 @@ impl<T> RawVec<T, Global> { /// `RawVec` with capacity `usize::MAX`. Useful for implementing /// delayed allocation. #[must_use] - #[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81"))] pub const fn new() -> Self { Self::new_in(Global) } @@ -179,7 +179,7 @@ impl<T, A: Allocator> RawVec<T, A> { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. #[inline] - #[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81"))] pub const fn new_in(alloc: A) -> Self { Self { inner: RawVecInner::new_in(alloc, align_of::<T>()), _marker: PhantomData } } @@ -409,7 +409,7 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> { impl<A: Allocator> RawVecInner<A> { #[inline] - #[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81"))] const fn new_in(alloc: A, align: usize) -> Self { let ptr = unsafe { core::mem::transmute(align) }; // `cap: 0` means "unallocated". zero-sized types are ignored. diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 128503284cd..9fdd51ce331 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -3075,7 +3075,7 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> { /// /// drop(strong); /// // But not any more. We can do weak.as_ptr(), but accessing the pointer would lead to - /// // undefined behaviour. + /// // undefined behavior. /// // assert_eq!("hello", unsafe { &*weak.as_ptr() }); /// ``` /// diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 220b79eaf8a..15a1b0f2834 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -804,7 +804,7 @@ impl<T, A: Allocator> Arc<T, A> { // observe a non-zero strong count. Therefore we need at least "Release" ordering // in order to synchronize with the `compare_exchange_weak` in `Weak::upgrade`. // - // "Acquire" ordering is not required. When considering the possible behaviours + // "Acquire" ordering is not required. When considering the possible behaviors // of `data_fn` we only need to look at what it could do with a reference to a // non-upgradeable `Weak`: // - It can *clone* the `Weak`, increasing the weak reference count. @@ -2788,7 +2788,7 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> { /// /// drop(strong); /// // But not any more. We can do weak.as_ptr(), but accessing the pointer would lead to - /// // undefined behaviour. + /// // undefined behavior. /// // assert_eq!("hello", unsafe { &*weak.as_ptr() }); /// ``` /// diff --git a/library/alloc/src/vec/is_zero.rs b/library/alloc/src/vec/is_zero.rs index bcc5bf4d65b..ba57d940d8c 100644 --- a/library/alloc/src/vec/is_zero.rs +++ b/library/alloc/src/vec/is_zero.rs @@ -172,7 +172,7 @@ macro_rules! impl_is_zero_option_of_bool { fn is_zero(&self) -> bool { // SAFETY: This is *not* a stable layout guarantee, but // inside `core` we're allowed to rely on the current rustc - // behaviour that options of bools will be one byte with + // behavior that options of bools will be one byte with // no padding, so long as they're nested less than 254 deep. let raw: u8 = unsafe { core::mem::transmute(*self) }; raw == 0 diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index 68f00d07529..8f48af24557 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -173,7 +173,7 @@ pub unsafe trait GlobalAlloc { /// # Safety /// /// The caller has to ensure that `layout` has non-zero size. Like `alloc` - /// zero sized `layout` can result in undefined behaviour. + /// zero sized `layout` can result in undefined behavior. /// However the allocated block of memory is guaranteed to be initialized. /// /// # Errors @@ -234,7 +234,7 @@ pub unsafe trait GlobalAlloc { /// does not overflow `isize` (i.e., the rounded value must be less than or /// equal to `isize::MAX`). /// - /// If these are not followed, undefined behaviour can result. + /// If these are not followed, undefined behavior can result. /// /// (Extension subtraits might provide more specific bounds on /// behavior, e.g., guarantee a sentinel address or a null pointer diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index fca32b9d3c5..95cf9427e02 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -66,7 +66,6 @@ impl Layout { #[stable(feature = "alloc_layout", since = "1.28.0")] #[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")] #[inline] - #[rustc_allow_const_fn_unstable(ptr_alignment_type)] pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutError> { if Layout::is_size_align_valid(size, align) { // SAFETY: Layout::is_size_align_valid checks the preconditions for this call. @@ -127,7 +126,6 @@ impl Layout { #[rustc_const_stable(feature = "const_alloc_layout_unchecked", since = "1.36.0")] #[must_use] #[inline] - #[rustc_allow_const_fn_unstable(ptr_alignment_type)] pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { assert_unsafe_precondition!( check_library_ub, @@ -159,7 +157,7 @@ impl Layout { #[must_use = "this returns the minimum alignment, \ without modifying the layout"] #[inline] - #[rustc_allow_const_fn_unstable(ptr_alignment_type)] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(ptr_alignment_type))] pub const fn align(&self) -> usize { self.align.as_usize() } diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index e1fa43296d0..0b106244793 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1221,7 +1221,7 @@ impl<T: ?Sized> RefCell<T> { /// Unlike `RefCell::borrow`, this method is unsafe because it does not /// return a `Ref`, thus leaving the borrow flag untouched. Mutably /// borrowing the `RefCell` while the reference returned by this method - /// is alive is undefined behaviour. + /// is alive is undefined behavior. /// /// # Examples /// @@ -2287,6 +2287,7 @@ impl<T> SyncUnsafeCell<T> { /// Unwraps the value, consuming the cell. #[inline] + #[rustc_const_unstable(feature = "sync_unsafe_cell", issue = "95439")] pub const fn into_inner(self) -> T { self.value.into_inner() } diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs index d323fbeac9c..5ac33516684 100644 --- a/library/core/src/cell/lazy.rs +++ b/library/core/src/cell/lazy.rs @@ -79,6 +79,7 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> { /// assert_eq!(LazyCell::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string())); /// ``` #[unstable(feature = "lazy_cell_into_inner", issue = "125623")] + #[rustc_const_unstable(feature = "lazy_cell_into_inner", issue = "125623")] pub const fn into_inner(this: Self) -> Result<T, F> { match this.state.into_inner() { State::Init(data) => Ok(data), diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 30c0fff3104..9c667edb476 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1770,7 +1770,7 @@ const fn len_utf16(code: u32) -> usize { /// Panics if the buffer is not large enough. /// A buffer of length four is large enough to encode any `char`. #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] -#[rustc_const_stable(feature = "const_char_encode_utf8", since = "1.83.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_char_encode_utf8", since = "1.83.0"))] #[doc(hidden)] #[inline] #[rustc_allow_const_fn_unstable(const_eval_select)] diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 4377b4993b8..5a3b9365cd2 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -380,7 +380,7 @@ pub struct AssertParamIsEq<T: Eq + ?Sized> { #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] #[stable(feature = "rust1", since = "1.0.0")] // This is a lang item only so that `BinOp::Cmp` in MIR can return it. -// It has no special behaviour, but does require that the three variants +// It has no special behavior, but does require that the three variants // `Less`/`Equal`/`Greater` remain `-1_i8`/`0_i8`/`+1_i8` respectively. #[lang = "Ordering"] #[repr(i8)] diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 15b00b9aa44..0f4386190ee 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -137,11 +137,11 @@ enum FromBytesWithNulErrorKind { // FIXME: const stability attributes should not be required here, I think impl FromBytesWithNulError { - #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0"))] const fn interior_nul(pos: usize) -> FromBytesWithNulError { FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) } } - #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0"))] const fn not_nul_terminated() -> FromBytesWithNulError { FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated } } @@ -730,7 +730,7 @@ impl AsRef<CStr> for CStr { /// located within `isize::MAX` from `ptr`. #[inline] #[unstable(feature = "cstr_internals", issue = "none")] -#[rustc_const_stable(feature = "const_cstr_from_ptr", since = "1.81.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_from_ptr", since = "1.81.0"))] #[rustc_allow_const_fn_unstable(const_eval_select)] const unsafe fn strlen(ptr: *const c_char) -> usize { const fn strlen_ct(s: *const c_char) -> usize { diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 4cbcfb07795..f3b54230bc1 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -333,7 +333,10 @@ pub struct Arguments<'a> { #[unstable(feature = "fmt_internals", issue = "none")] impl<'a> Arguments<'a> { #[inline] - #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] + #[cfg_attr( + bootstrap, + rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none") + )] pub const fn new_const<const N: usize>(pieces: &'a [&'static str; N]) -> Self { const { assert!(N <= 1) }; Arguments { pieces, fmt: None, args: &[] } @@ -438,6 +441,7 @@ impl<'a> Arguments<'a> { #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "103900")] #[must_use] #[inline] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] pub const fn as_str(&self) -> Option<&'static str> { match (self.pieces, self.args) { ([], []) => Some(""), diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index a69f0afdb0a..78df51f2bc4 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -506,7 +506,7 @@ pub const fn black_box<T>(dummy: T) -> T { /// # } /// ``` #[unstable(feature = "hint_must_use", issue = "94745")] -#[rustc_const_unstable(feature = "hint_must_use", issue = "94745")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "hint_must_use", issue = "94745"))] #[must_use] // <-- :) #[inline(always)] pub const fn must_use<T>(value: T) -> T { diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 97e727633c5..fc09da7bcbc 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -14,9 +14,10 @@ //! `#[rustc_const_unstable(feature = "const_such_and_such", issue = "01234")]` to the intrinsic declaration. //! //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute, -//! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done -//! without T-lang consultation, because it bakes a feature into the language that cannot be -//! replicated in user code without compiler support. +//! `#[rustc_const_stable_indirect]` needs to be added to the intrinsic (`#[rustc_const_unstable]` +//! can be removed then). Such a change should not be done without T-lang consultation, because it +//! may bake a feature into the language that cannot be replicated in user code without compiler +//! support. //! //! # Volatiles //! @@ -930,7 +931,7 @@ extern "rust-intrinsic" { /// on most platforms. /// On Unix, the /// process will probably terminate with a signal like `SIGABRT`, `SIGILL`, `SIGTRAP`, `SIGSEGV` or - /// `SIGBUS`. The precise behaviour is not guaranteed and not stable. + /// `SIGBUS`. The precise behavior is not guaranteed and not stable. #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn abort() -> !; @@ -943,7 +944,11 @@ extern "rust-intrinsic" { /// reach code marked with this function. /// /// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`]. - #[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")] + #[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0") + )] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn unreachable() -> !; } @@ -958,7 +963,8 @@ extern "rust-intrinsic" { /// own, or if it does not enable any significant optimizations. /// /// The stabilized version of this intrinsic is [`core::hint::assert_unchecked`]. -#[rustc_const_stable(feature = "const_assume", since = "1.77.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assume", since = "1.77.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] @@ -980,7 +986,11 @@ pub const unsafe fn assume(b: bool) { /// any safety invariants. /// /// This intrinsic does not have a stable counterpart. -#[rustc_const_unstable(feature = "const_likely", issue = "none")] +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION") +)] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] #[rustc_nounwind] @@ -1000,7 +1010,11 @@ pub const fn likely(b: bool) -> bool { /// any safety invariants. /// /// This intrinsic does not have a stable counterpart. -#[rustc_const_unstable(feature = "const_likely", issue = "none")] +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION") +)] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] #[rustc_nounwind] @@ -1041,7 +1055,8 @@ extern "rust-intrinsic" { /// This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. - #[rustc_const_stable(feature = "const_assert_type", since = "1.59.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type", since = "1.59.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn assert_inhabited<T>(); @@ -1050,7 +1065,8 @@ extern "rust-intrinsic" { /// zero-initialization: This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. - #[rustc_const_stable(feature = "const_assert_type2", since = "1.75.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn assert_zero_valid<T>(); @@ -1058,7 +1074,8 @@ extern "rust-intrinsic" { /// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. - #[rustc_const_stable(feature = "const_assert_type2", since = "1.75.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn assert_mem_uninitialized_valid<T>(); @@ -1071,7 +1088,8 @@ extern "rust-intrinsic" { /// any safety invariants. /// /// Consider using [`core::panic::Location::caller`] instead. - #[rustc_const_stable(feature = "const_caller_location", since = "1.79.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_caller_location", since = "1.79.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn caller_location() -> &'static crate::panic::Location<'static>; @@ -1085,7 +1103,8 @@ extern "rust-intrinsic" { /// it does not require an `unsafe` block. /// Therefore, implementations must not require the user to uphold /// any safety invariants. - #[rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn forget<T: ?Sized>(_: T); @@ -1384,14 +1403,15 @@ extern "rust-intrinsic" { /// Like [`transmute`], but even less checked at compile-time: rather than /// giving an error for `size_of::<Src>() != size_of::<Dst>()`, it's - /// **Undefined Behaviour** at runtime. + /// **Undefined Behavior** at runtime. /// /// Prefer normal `transmute` where possible, for the extra checking, since /// both do exactly the same thing at runtime, if they both compile. /// /// This is not expected to ever be exposed directly to users, rather it /// may eventually be exposed through some more-constrained API. - #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_transmute", since = "1.56.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn transmute_unchecked<Src, Dst>(src: Src) -> Dst; @@ -1408,7 +1428,8 @@ extern "rust-intrinsic" { /// any safety invariants. /// /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop). - #[rustc_const_stable(feature = "const_needs_drop", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_needs_drop", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn needs_drop<T: ?Sized>() -> bool; @@ -1430,7 +1451,8 @@ extern "rust-intrinsic" { /// /// The stabilized version of this intrinsic is [`pointer::offset`]. #[must_use = "returns a new pointer rather than modifying its argument"] - #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn offset<Ptr, Delta>(dst: Ptr, offset: Delta) -> Ptr; @@ -1448,7 +1470,8 @@ extern "rust-intrinsic" { /// /// The stabilized version of this intrinsic is [`pointer::wrapping_offset`]. #[must_use = "returns a new pointer rather than modifying its argument"] - #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T; @@ -2131,7 +2154,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `count_ones` method. For example, /// [`u32::count_ones`] - #[rustc_const_stable(feature = "const_ctpop", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctpop", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn ctpop<T: Copy>(x: T) -> u32; @@ -2172,7 +2196,8 @@ extern "rust-intrinsic" { /// let num_leading = ctlz(x); /// assert_eq!(num_leading, 16); /// ``` - #[rustc_const_stable(feature = "const_ctlz", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctlz", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn ctlz<T: Copy>(x: T) -> u32; @@ -2194,7 +2219,8 @@ extern "rust-intrinsic" { /// let num_leading = unsafe { ctlz_nonzero(x) }; /// assert_eq!(num_leading, 3); /// ``` - #[rustc_const_stable(feature = "constctlz", since = "1.50.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "constctlz", since = "1.50.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn ctlz_nonzero<T: Copy>(x: T) -> u32; @@ -2234,7 +2260,8 @@ extern "rust-intrinsic" { /// let num_trailing = cttz(x); /// assert_eq!(num_trailing, 16); /// ``` - #[rustc_const_stable(feature = "const_cttz", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn cttz<T: Copy>(x: T) -> u32; @@ -2256,7 +2283,8 @@ extern "rust-intrinsic" { /// let num_trailing = unsafe { cttz_nonzero(x) }; /// assert_eq!(num_trailing, 3); /// ``` - #[rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn cttz_nonzero<T: Copy>(x: T) -> u32; @@ -2270,7 +2298,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `swap_bytes` method. For example, /// [`u32::swap_bytes`] - #[rustc_const_stable(feature = "const_bswap", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bswap", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn bswap<T: Copy>(x: T) -> T; @@ -2285,7 +2314,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `reverse_bits` method. For example, /// [`u32::reverse_bits`] - #[rustc_const_stable(feature = "const_bitreverse", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bitreverse", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn bitreverse<T: Copy>(x: T) -> T; @@ -2311,7 +2341,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `overflowing_add` method. For example, /// [`u32::overflowing_add`] - #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn add_with_overflow<T: Copy>(x: T, y: T) -> (T, bool); @@ -2326,7 +2357,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `overflowing_sub` method. For example, /// [`u32::overflowing_sub`] - #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn sub_with_overflow<T: Copy>(x: T, y: T) -> (T, bool); @@ -2341,7 +2373,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `overflowing_mul` method. For example, /// [`u32::overflowing_mul`] - #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn mul_with_overflow<T: Copy>(x: T, y: T) -> (T, bool); @@ -2360,7 +2393,11 @@ extern "rust-intrinsic" { /// Safe wrappers for this intrinsic are available on the integer /// primitives via the `checked_div` method. For example, /// [`u32::checked_div`] - #[rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0")] + #[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0") + )] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn unchecked_div<T: Copy>(x: T, y: T) -> T; /// Returns the remainder of an unchecked division, resulting in @@ -2369,7 +2406,11 @@ extern "rust-intrinsic" { /// Safe wrappers for this intrinsic are available on the integer /// primitives via the `checked_rem` method. For example, /// [`u32::checked_rem`] - #[rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0")] + #[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0") + )] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn unchecked_rem<T: Copy>(x: T, y: T) -> T; @@ -2379,7 +2420,8 @@ extern "rust-intrinsic" { /// Safe wrappers for this intrinsic are available on the integer /// primitives via the `checked_shl` method. For example, /// [`u32::checked_shl`] - #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn unchecked_shl<T: Copy, U: Copy>(x: T, y: U) -> T; /// Performs an unchecked right shift, resulting in undefined behavior when @@ -2388,7 +2430,8 @@ extern "rust-intrinsic" { /// Safe wrappers for this intrinsic are available on the integer /// primitives via the `checked_shr` method. For example, /// [`u32::checked_shr`] - #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn unchecked_shr<T: Copy, U: Copy>(x: T, y: U) -> T; @@ -2397,7 +2440,8 @@ extern "rust-intrinsic" { /// /// The stable counterpart of this intrinsic is `unchecked_add` on the various /// integer types, such as [`u16::unchecked_add`] and [`i64::unchecked_add`]. - #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn unchecked_add<T: Copy>(x: T, y: T) -> T; @@ -2406,7 +2450,8 @@ extern "rust-intrinsic" { /// /// The stable counterpart of this intrinsic is `unchecked_sub` on the various /// integer types, such as [`u16::unchecked_sub`] and [`i64::unchecked_sub`]. - #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn unchecked_sub<T: Copy>(x: T, y: T) -> T; @@ -2415,7 +2460,8 @@ extern "rust-intrinsic" { /// /// The stable counterpart of this intrinsic is `unchecked_mul` on the various /// integer types, such as [`u16::unchecked_mul`] and [`i64::unchecked_mul`]. - #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn unchecked_mul<T: Copy>(x: T, y: T) -> T; @@ -2429,7 +2475,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `rotate_left` method. For example, /// [`u32::rotate_left`] - #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn rotate_left<T: Copy>(x: T, shift: u32) -> T; @@ -2444,7 +2491,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `rotate_right` method. For example, /// [`u32::rotate_right`] - #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn rotate_right<T: Copy>(x: T, shift: u32) -> T; @@ -2459,7 +2507,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_add` method. For example, /// [`u32::wrapping_add`] - #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn wrapping_add<T: Copy>(a: T, b: T) -> T; @@ -2473,7 +2522,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_sub` method. For example, /// [`u32::wrapping_sub`] - #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn wrapping_sub<T: Copy>(a: T, b: T) -> T; @@ -2487,7 +2537,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_mul` method. For example, /// [`u32::wrapping_mul`] - #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn wrapping_mul<T: Copy>(a: T, b: T) -> T; @@ -2502,7 +2553,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `saturating_add` method. For example, /// [`u32::saturating_add`] - #[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn saturating_add<T: Copy>(a: T, b: T) -> T; @@ -2516,7 +2568,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `saturating_sub` method. For example, /// [`u32::saturating_sub`] - #[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn saturating_sub<T: Copy>(a: T, b: T) -> T; @@ -2527,7 +2580,8 @@ extern "rust-intrinsic" { /// This intrinsic can *only* be called where the pointer is a local without /// projections (`read_via_copy(ptr)`, not `read_via_copy(*ptr)`) so that it /// trivially obeys runtime-MIR rules about derefs in operands. - #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_read", since = "1.71.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn read_via_copy<T>(ptr: *const T) -> T; @@ -2537,7 +2591,8 @@ extern "rust-intrinsic" { /// This intrinsic can *only* be called where the pointer is a local without /// projections (`write_via_move(ptr, x)`, not `write_via_move(*ptr, x)`) so /// that it trivially obeys runtime-MIR rules about derefs in operands. - #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn write_via_move<T>(ptr: *mut T, value: T); @@ -2550,7 +2605,8 @@ extern "rust-intrinsic" { /// any safety invariants. /// /// The stabilized version of this intrinsic is [`core::mem::discriminant`]. - #[rustc_const_stable(feature = "const_discriminant", since = "1.75.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_discriminant", since = "1.75.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant; @@ -2584,7 +2640,8 @@ extern "rust-intrinsic" { pub fn nontemporal_store<T>(ptr: *mut T, val: T); /// See documentation of `<*const T>::offset_from` for details. - #[rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize; @@ -2850,7 +2907,8 @@ pub const unsafe fn typed_swap<T>(x: *mut T, y: *mut T) { /// assertions are enabled whenever the *user crate* has UB checks enabled. However, if the /// user has UB checks disabled, the checks will still get optimized out. This intrinsic is /// primarily used by [`ub_checks::assert_unsafe_precondition`]. -#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // just for UB checks #[unstable(feature = "core_intrinsics", issue = "none")] #[inline(always)] #[rustc_intrinsic] @@ -2935,7 +2993,8 @@ pub unsafe fn vtable_align(_ptr: *const ()) -> usize { /// The stabilized version of this intrinsic is [`core::mem::size_of`]. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_stable(feature = "const_size_of", since = "1.40.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_size_of", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn size_of<T>() -> usize { @@ -2952,7 +3011,8 @@ pub const fn size_of<T>() -> usize { /// The stabilized version of this intrinsic is [`core::mem::align_of`]. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_min_align_of", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn min_align_of<T>() -> usize { @@ -3065,7 +3125,8 @@ pub const fn type_id<T: ?Sized + 'static>() -> u128 { /// change the possible layouts of pointers. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn aggregate_raw_ptr<P: AggregateRawPtr<D, Metadata = M>, D, M>(_data: D, _meta: M) -> P { @@ -3090,7 +3151,11 @@ impl<P: ?Sized, T: ptr::Thin> AggregateRawPtr<*mut T> for *mut P { /// This is used to implement functions like `ptr::metadata`. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")] +#[cfg_attr( + bootstrap, + cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")) +)] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *const P) -> M { @@ -3197,7 +3262,15 @@ pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *cons #[rustc_diagnostic_item = "ptr_copy_nonoverlapping"] pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] + #[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0") + )] + #[cfg_attr( + not(bootstrap), + rustc_const_unstable(feature = "core_intrinsics", issue = "none") + )] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize); } @@ -3301,7 +3374,15 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us #[rustc_diagnostic_item = "ptr_copy"] pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] + #[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0") + )] + #[cfg_attr( + not(bootstrap), + rustc_const_unstable(feature = "core_intrinsics", issue = "none") + )] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] fn copy<T>(src: *const T, dst: *mut T, count: usize); } @@ -3382,7 +3463,8 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) { #[rustc_diagnostic_item = "ptr_write_bytes"] pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) { extern "rust-intrinsic" { - #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] fn write_bytes<T>(dst: *mut T, val: u8, count: usize); } @@ -3643,6 +3725,7 @@ pub const unsafe fn copysignf128(_x: f128, _y: f128) -> f128 { /// Inform Miri that a given pointer definitely has a certain alignment. #[cfg(miri)] +#[rustc_allow_const_fn_unstable(const_eval_select)] pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize) { extern "Rust" { /// Miri-provided extern function to promise that a given pointer is properly aligned for diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index a2ab39caade..6539964bc09 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -298,7 +298,7 @@ define!( ); define!( "mir_unwind_unreachable", - /// An unwind action that triggers undefined behaviour. + /// An unwind action that triggers undefined behavior. fn UnwindUnreachable() -> UnwindActionArg ); define!( diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 86660f2e375..2cf2ea58fd4 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -346,7 +346,6 @@ pub trait IntoIterator { fn into_iter(self) -> Self::IntoIter; } -#[rustc_const_unstable(feature = "const_intoiterator_identity", issue = "90603")] #[stable(feature = "rust1", since = "1.0.0")] impl<I: Iterator> IntoIterator for I { type Item = I::Item; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 16877566765..9c3bf827438 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -107,6 +107,7 @@ // // Library features: // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(const_fmt_arguments_new))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] #![feature(const_align_of_val)] @@ -121,11 +122,8 @@ #![feature(const_eval_select)] #![feature(const_exact_div)] #![feature(const_float_methods)] -#![feature(const_fmt_arguments_new)] #![feature(const_hash)] #![feature(const_heap)] -#![feature(const_index_range_slice_index)] -#![feature(const_likely)] #![feature(const_nonnull_new)] #![feature(const_num_midpoint)] #![feature(const_option_ext)] @@ -144,6 +142,7 @@ #![feature(const_typed_swap)] #![feature(const_ub_checks)] #![feature(const_unicode_case_lookup)] +#![feature(core_intrinsics)] #![feature(coverage_attribute)] #![feature(do_not_recommend)] #![feature(internal_impls_macro)] @@ -159,6 +158,7 @@ #![feature(ptr_alignment_type)] #![feature(ptr_metadata)] #![feature(set_ptr_value)] +#![feature(slice_as_chunks)] #![feature(slice_ptr_get)] #![feature(str_internals)] #![feature(str_split_inclusive_remainder)] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index ea73cfc3781..b4252ef0103 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -723,7 +723,7 @@ impl<T> MaybeUninit<T> { /// this does not constitute a stable guarantee), because the only /// requirement the compiler knows about it is that the data pointer must be /// non-null. Dropping such a `Vec<T>` however will cause undefined - /// behaviour. + /// behavior. /// /// [`assume_init`]: MaybeUninit::assume_init /// [`Vec<T>`]: ../../std/vec/struct.Vec.html diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index d3360c18207..0d1f4a9ea3e 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -373,6 +373,7 @@ impl IpAddr { /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0)).is_benchmarking(), true); /// ``` #[unstable(feature = "ip", issue = "27709")] + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[must_use] #[inline] pub const fn is_benchmarking(&self) -> bool { diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 5ab2ab50d7c..e8161cce2fe 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -288,7 +288,6 @@ impl f128 { // concerns about portability, so this implementation is for // private use internally. #[inline] - #[rustc_const_unstable(feature = "f128", issue = "116909")] pub(crate) const fn abs_private(self) -> f128 { // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`. unsafe { @@ -319,7 +318,6 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn is_infinite(self) -> bool { (self == f128::INFINITY) | (self == f128::NEG_INFINITY) } @@ -346,7 +344,6 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn is_finite(self) -> bool { // There's no need to handle NaN separately: if self is NaN, // the comparison is not true, exactly as desired. @@ -380,7 +377,6 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn is_subnormal(self) -> bool { matches!(self.classify(), FpCategory::Subnormal) } @@ -412,7 +408,6 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn is_normal(self) -> bool { matches!(self.classify(), FpCategory::Normal) } @@ -437,7 +432,6 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn classify(self) -> FpCategory { let bits = self.to_bits(); match (bits & Self::MAN_MASK, bits & Self::EXP_MASK) { @@ -915,7 +909,6 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_bits(self) -> u128 { // SAFETY: `u128` is a plain old datatype so we can always transmute to it. @@ -964,7 +957,6 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn from_bits(v: u128) -> Self { // It turns out the safety issues with sNaN were overblown! Hooray! // SAFETY: `u128` is a plain old datatype so we can always transmute from it. @@ -991,7 +983,6 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_be_bytes(self) -> [u8; 16] { self.to_bits().to_be_bytes() @@ -1017,7 +1008,6 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_le_bytes(self) -> [u8; 16] { self.to_bits().to_le_bytes() @@ -1054,7 +1044,6 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_ne_bytes(self) -> [u8; 16] { self.to_bits().to_ne_bytes() @@ -1082,7 +1071,6 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn from_be_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_be_bytes(bytes)) } @@ -1109,7 +1097,6 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn from_le_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_le_bytes(bytes)) } @@ -1146,7 +1133,6 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn from_ne_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_ne_bytes(bytes)) } diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 60a88496696..8b3f3b7d19b 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -282,7 +282,6 @@ impl f16 { // concerns about portability, so this implementation is for // private use internally. #[inline] - #[rustc_const_unstable(feature = "f16", issue = "116909")] pub(crate) const fn abs_private(self) -> f16 { // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`. unsafe { mem::transmute::<u16, f16>(mem::transmute::<f16, u16>(self) & !Self::SIGN_MASK) } @@ -310,7 +309,6 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn is_infinite(self) -> bool { (self == f16::INFINITY) | (self == f16::NEG_INFINITY) } @@ -336,7 +334,6 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn is_finite(self) -> bool { // There's no need to handle NaN separately: if self is NaN, // the comparison is not true, exactly as desired. @@ -368,7 +365,6 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn is_subnormal(self) -> bool { matches!(self.classify(), FpCategory::Subnormal) } @@ -398,7 +394,6 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn is_normal(self) -> bool { matches!(self.classify(), FpCategory::Normal) } @@ -422,7 +417,6 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn classify(self) -> FpCategory { let b = self.to_bits(); match (b & Self::MAN_MASK, b & Self::EXP_MASK) { @@ -901,7 +895,6 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_bits(self) -> u16 { // SAFETY: `u16` is a plain old datatype so we can always transmute to it. @@ -949,7 +942,6 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn from_bits(v: u16) -> Self { // It turns out the safety issues with sNaN were overblown! Hooray! // SAFETY: `u16` is a plain old datatype so we can always transmute from it. @@ -975,7 +967,6 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_be_bytes(self) -> [u8; 2] { self.to_bits().to_be_bytes() @@ -1000,7 +991,6 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_le_bytes(self) -> [u8; 2] { self.to_bits().to_le_bytes() @@ -1038,7 +1028,6 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_ne_bytes(self) -> [u8; 2] { self.to_bits().to_ne_bytes() @@ -1062,7 +1051,6 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn from_be_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_be_bytes(bytes)) } @@ -1085,7 +1073,6 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn from_le_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_le_bytes(bytes)) } @@ -1119,7 +1106,6 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn from_ne_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_ne_bytes(bytes)) } diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 7241b3ff6a3..1d640ea74c4 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -449,7 +449,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_add(self, rhs: Self) -> Option<Self> { let (a, b) = self.overflowing_add(rhs); - if unlikely!(b) { None } else { Some(a) } + if intrinsics::unlikely(b) { None } else { Some(a) } } /// Strict integer addition. Computes `self + rhs`, panicking @@ -545,7 +545,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_add_unsigned(self, rhs: $UnsignedT) -> Option<Self> { let (a, b) = self.overflowing_add_unsigned(rhs); - if unlikely!(b) { None } else { Some(a) } + if intrinsics::unlikely(b) { None } else { Some(a) } } /// Strict addition with an unsigned integer. Computes `self + rhs`, @@ -601,7 +601,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_sub(self, rhs: Self) -> Option<Self> { let (a, b) = self.overflowing_sub(rhs); - if unlikely!(b) { None } else { Some(a) } + if intrinsics::unlikely(b) { None } else { Some(a) } } /// Strict integer subtraction. Computes `self - rhs`, panicking if @@ -697,7 +697,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_sub_unsigned(self, rhs: $UnsignedT) -> Option<Self> { let (a, b) = self.overflowing_sub_unsigned(rhs); - if unlikely!(b) { None } else { Some(a) } + if intrinsics::unlikely(b) { None } else { Some(a) } } /// Strict subtraction with an unsigned integer. Computes `self - rhs`, @@ -753,7 +753,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_mul(self, rhs: Self) -> Option<Self> { let (a, b) = self.overflowing_mul(rhs); - if unlikely!(b) { None } else { Some(a) } + if intrinsics::unlikely(b) { None } else { Some(a) } } /// Strict integer multiplication. Computes `self * rhs`, panicking if @@ -849,7 +849,7 @@ macro_rules! int_impl { without modifying the original"] #[inline] pub const fn checked_div(self, rhs: Self) -> Option<Self> { - if unlikely!(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) { + if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) { None } else { // SAFETY: div by zero and by INT_MIN have been checked above @@ -924,7 +924,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> { // Using `&` helps LLVM see that it is the same check made in division. - if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) { + if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) { None } else { Some(self.div_euclid(rhs)) @@ -997,7 +997,7 @@ macro_rules! int_impl { without modifying the original"] #[inline] pub const fn checked_rem(self, rhs: Self) -> Option<Self> { - if unlikely!(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) { + if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) { None } else { // SAFETY: div by zero and by INT_MIN have been checked above @@ -1071,7 +1071,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> { // Using `&` helps LLVM see that it is the same check made in division. - if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) { + if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) { None } else { Some(self.rem_euclid(rhs)) @@ -1142,7 +1142,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_neg(self) -> Option<Self> { let (a, b) = self.overflowing_neg(); - if unlikely!(b) { None } else { Some(a) } + if intrinsics::unlikely(b) { None } else { Some(a) } } /// Unchecked negation. Computes `-self`, assuming overflow cannot occur. @@ -2564,7 +2564,7 @@ macro_rules! int_impl { without modifying the original"] pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { // Using `&` helps LLVM see that it is the same check made in division. - if unlikely!((self == Self::MIN) & (rhs == -1)) { + if intrinsics::unlikely((self == Self::MIN) & (rhs == -1)) { (self, true) } else { (self / rhs, false) @@ -2595,7 +2595,7 @@ macro_rules! int_impl { without modifying the original"] pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { // Using `&` helps LLVM see that it is the same check made in division. - if unlikely!((self == Self::MIN) & (rhs == -1)) { + if intrinsics::unlikely((self == Self::MIN) & (rhs == -1)) { (self, true) } else { (self.div_euclid(rhs), false) @@ -2625,7 +2625,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { - if unlikely!(rhs == -1) { + if intrinsics::unlikely(rhs == -1) { (0, self == Self::MIN) } else { (self % rhs, false) @@ -2657,7 +2657,7 @@ macro_rules! int_impl { #[inline] #[track_caller] pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { - if unlikely!(rhs == -1) { + if intrinsics::unlikely(rhs == -1) { (0, self == Self::MIN) } else { (self.rem_euclid(rhs), false) @@ -2686,7 +2686,7 @@ macro_rules! int_impl { without modifying the original"] #[allow(unused_attributes)] pub const fn overflowing_neg(self) -> (Self, bool) { - if unlikely!(self == Self::MIN) { + if intrinsics::unlikely(self == Self::MIN) { (Self::MIN, true) } else { (-self, false) diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 5e2f45884dd..f95cfd33ae5 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -16,13 +16,6 @@ macro_rules! try_opt { }; } -#[allow_internal_unstable(const_likely)] -macro_rules! unlikely { - ($e: expr) => { - intrinsics::unlikely($e) - }; -} - // Use this when the generated code should differ between signed and unsigned types. macro_rules! sign_dependent_expr { (signed ? if signed { $signed_case:expr } if unsigned { $unsigned_case:expr } ) => { @@ -1397,7 +1390,7 @@ from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 } #[doc(hidden)] #[inline(always)] #[unstable(issue = "none", feature = "std_internals")] -#[rustc_const_stable(feature = "const_int_from_str", since = "1.82.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_from_str", since = "1.82.0"))] pub const fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool { radix <= 16 && digits.len() <= mem::size_of::<T>() * 2 - is_signed_ty as usize } @@ -1416,6 +1409,7 @@ fn from_str_radix_panic_rt(radix: u32) -> ! { #[cfg_attr(feature = "panic_immediate_abort", inline)] #[cold] #[track_caller] +#[rustc_allow_const_fn_unstable(const_eval_select)] const fn from_str_radix_panic(radix: u32) { // The only difference between these two functions is their panic message. intrinsics::const_eval_select((radix,), from_str_radix_panic_ct, from_str_radix_panic_rt); diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index e5c9a7e086a..fdb84827e27 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -355,7 +355,7 @@ where } /// Creates a non-zero without checking whether the value is non-zero. - /// This results in undefined behaviour if the value is zero. + /// This results in undefined behavior if the value is zero. /// /// # Safety /// @@ -952,9 +952,9 @@ macro_rules! nonzero_integer { /// Multiplies two non-zero integers together, /// assuming overflow cannot occur. - /// Overflow is unchecked, and it is undefined behaviour to overflow + /// Overflow is unchecked, and it is undefined behavior to overflow /// *even if the result would wrap to a non-zero value*. - /// The behaviour is undefined as soon as + /// The behavior is undefined as soon as #[doc = sign_dependent_expr!{ $signedness ? if signed { @@ -1323,9 +1323,9 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// Adds an unsigned integer to a non-zero value, /// assuming overflow cannot occur. - /// Overflow is unchecked, and it is undefined behaviour to overflow + /// Overflow is unchecked, and it is undefined behavior to overflow /// *even if the result would wrap to a non-zero value*. - /// The behaviour is undefined as soon as + /// The behavior is undefined as soon as #[doc = concat!("`self + rhs > ", stringify!($Int), "::MAX`.")] /// /// # Examples @@ -1599,7 +1599,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// Computes the absolute value of self. #[doc = concat!("See [`", stringify!($Int), "::abs`]")] - /// for documentation on overflow behaviour. + /// for documentation on overflow behavior. /// /// # Example /// @@ -1878,7 +1878,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// Negates self, overflowing if this is equal to the minimum value. /// #[doc = concat!("See [`", stringify!($Int), "::overflowing_neg`]")] - /// for documentation on overflow behaviour. + /// for documentation on overflow behavior. /// /// # Example /// @@ -1943,7 +1943,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// of the type. /// #[doc = concat!("See [`", stringify!($Int), "::wrapping_neg`]")] - /// for documentation on overflow behaviour. + /// for documentation on overflow behavior. /// /// # Example /// diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index d9036abecc5..9c5fe563d93 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -491,7 +491,7 @@ macro_rules! uint_impl { // Per <https://github.com/rust-lang/rust/pull/124114#issuecomment-2066173305>, // LLVM is happy to re-form the intrinsic later if useful. - if unlikely!(intrinsics::add_with_overflow(self, rhs).1) { + if intrinsics::unlikely(intrinsics::add_with_overflow(self, rhs).1) { None } else { // SAFETY: Just checked it doesn't overflow @@ -593,7 +593,7 @@ macro_rules! uint_impl { #[inline] pub const fn checked_add_signed(self, rhs: $SignedT) -> Option<Self> { let (a, b) = self.overflowing_add_signed(rhs); - if unlikely!(b) { None } else { Some(a) } + if intrinsics::unlikely(b) { None } else { Some(a) } } /// Strict addition with a signed integer. Computes `self + rhs`, @@ -845,7 +845,7 @@ macro_rules! uint_impl { #[inline] pub const fn checked_mul(self, rhs: Self) -> Option<Self> { let (a, b) = self.overflowing_mul(rhs); - if unlikely!(b) { None } else { Some(a) } + if intrinsics::unlikely(b) { None } else { Some(a) } } /// Strict integer multiplication. Computes `self * rhs`, panicking if @@ -940,7 +940,7 @@ macro_rules! uint_impl { without modifying the original"] #[inline] pub const fn checked_div(self, rhs: Self) -> Option<Self> { - if unlikely!(rhs == 0) { + if intrinsics::unlikely(rhs == 0) { None } else { // SAFETY: div by zero has been checked above and unsigned types have no other @@ -1001,7 +1001,7 @@ macro_rules! uint_impl { without modifying the original"] #[inline] pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> { - if unlikely!(rhs == 0) { + if intrinsics::unlikely(rhs == 0) { None } else { Some(self.div_euclid(rhs)) @@ -1061,7 +1061,7 @@ macro_rules! uint_impl { without modifying the original"] #[inline] pub const fn checked_rem(self, rhs: Self) -> Option<Self> { - if unlikely!(rhs == 0) { + if intrinsics::unlikely(rhs == 0) { None } else { // SAFETY: div by zero has been checked above and unsigned types have no other @@ -1123,7 +1123,7 @@ macro_rules! uint_impl { without modifying the original"] #[inline] pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> { - if unlikely!(rhs == 0) { + if intrinsics::unlikely(rhs == 0) { None } else { Some(self.rem_euclid(rhs)) @@ -1362,7 +1362,7 @@ macro_rules! uint_impl { #[inline] pub const fn checked_neg(self) -> Option<Self> { let (a, b) = self.overflowing_neg(); - if unlikely!(b) { None } else { Some(a) } + if intrinsics::unlikely(b) { None } else { Some(a) } } /// Strict negation. Computes `-self`, panicking unless `self == @@ -3009,7 +3009,7 @@ macro_rules! uint_impl { // overflow cases it instead ends up returning the maximum value // of the type, and can return 0 for 0. #[inline] - #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_pow", since = "1.50.0"))] const fn one_less_than_next_power_of_two(self) -> Self { if self <= 1 { return 0; } @@ -3086,7 +3086,7 @@ macro_rules! uint_impl { /// ``` #[inline] #[unstable(feature = "wrapping_next_power_of_two", issue = "32463", - reason = "needs decision on wrapping behaviour")] + reason = "needs decision on wrapping behavior")] #[rustc_const_unstable(feature = "wrapping_next_power_of_two", issue = "32463")] #[must_use = "this returns the result of the operation, \ without modifying the original"] diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs index 1ac6d3161c2..1156b389e28 100644 --- a/library/core/src/num/wrapping.rs +++ b/library/core/src/num/wrapping.rs @@ -1043,7 +1043,7 @@ macro_rules! wrapping_int_impl_unsigned { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[unstable(feature = "wrapping_next_power_of_two", issue = "32463", - reason = "needs decision on wrapping behaviour")] + reason = "needs decision on wrapping behavior")] pub fn next_power_of_two(self) -> Self { Wrapping(self.0.wrapping_next_power_of_two()) } diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 49b380e4574..1ef9990c00a 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -15,7 +15,7 @@ /// /// Types that implement `Deref` or `DerefMut` are often called "smart /// pointers" and the mechanism of deref coercion has been specifically designed -/// to facilitate the pointer-like behaviour that name suggests. Often, the +/// to facilitate the pointer-like behavior that name suggests. Often, the /// purpose of a "smart pointer" type is to change the ownership semantics /// of a contained value (for example, [`Rc`][rc] or [`Cow`][cow]) or the /// storage semantics of a contained value (for example, [`Box`][box]). @@ -42,7 +42,7 @@ /// 1. a value of the type transparently behaves like a value of the target /// type; /// 1. the implementation of the deref function is cheap; and -/// 1. users of the type will not be surprised by any deref coercion behaviour. +/// 1. users of the type will not be surprised by any deref coercion behavior. /// /// In general, deref traits **should not** be implemented if: /// @@ -185,7 +185,7 @@ impl<T: ?Sized> Deref for &mut T { /// /// Types that implement `DerefMut` or `Deref` are often called "smart /// pointers" and the mechanism of deref coercion has been specifically designed -/// to facilitate the pointer-like behaviour that name suggests. Often, the +/// to facilitate the pointer-like behavior that name suggests. Often, the /// purpose of a "smart pointer" type is to change the ownership semantics /// of a contained value (for example, [`Rc`][rc] or [`Cow`][cow]) or the /// storage semantics of a contained value (for example, [`Box`][box]). diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 0b996c40c04..2aa4f172368 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -150,7 +150,7 @@ //! It is further guaranteed that, for the cases above, one can //! [`mem::transmute`] from all valid values of `T` to `Option<T>` and //! from `Some::<T>(_)` to `T` (but transmuting `None::<T>` to `T` -//! is undefined behaviour). +//! is undefined behavior). //! //! # Method overview //! diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs index af2c83b5460..1d950eb3625 100644 --- a/library/core/src/panic/panic_info.rs +++ b/library/core/src/panic/panic_info.rs @@ -168,6 +168,7 @@ impl<'a> PanicMessage<'a> { #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "103900")] #[must_use] #[inline] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] pub const fn as_str(&self) -> Option<&'static str> { self.message.as_str() } diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 7420579e3ce..9071d6719a3 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -50,7 +50,8 @@ const _: () = assert!(cfg!(panic = "abort"), "panic_immediate_abort requires -C #[track_caller] #[lang = "panic_fmt"] // needed for const-evaluated panics #[rustc_do_not_const_check] // hooked by const-eval -#[rustc_const_unstable(feature = "panic_internals", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { if cfg!(feature = "panic_immediate_abort") { super::intrinsics::abort() @@ -84,7 +85,9 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { // and unwinds anyway, we will hit the "unwinding out of nounwind function" guard, // which causes a "panic in a function that cannot unwind". #[rustc_nounwind] -#[rustc_const_unstable(feature = "panic_internals", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable +#[rustc_allow_const_fn_unstable(const_eval_select)] pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! { #[inline] // this should always be inlined into `panic_nounwind_fmt` #[track_caller] @@ -131,7 +134,8 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] -#[rustc_const_unstable(feature = "panic_internals", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable #[lang = "panic"] // used by lints and miri for panics pub const fn panic(expr: &'static str) -> ! { // Use Arguments::new_const instead of format_args!("{expr}") to potentially @@ -169,7 +173,8 @@ macro_rules! panic_const { #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] - #[rustc_const_unstable(feature = "panic_internals", issue = "none")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable #[lang = stringify!($lang)] pub const fn $lang() -> ! { // Use Arguments::new_const instead of format_args!("{expr}") to potentially @@ -216,7 +221,8 @@ panic_const! { #[cfg_attr(feature = "panic_immediate_abort", inline)] #[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics #[rustc_nounwind] -#[rustc_const_unstable(feature = "panic_internals", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable pub const fn panic_nounwind(expr: &'static str) -> ! { panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ false); } @@ -232,7 +238,8 @@ pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! { #[track_caller] #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] -#[rustc_const_unstable(feature = "panic_internals", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable pub const fn panic_explicit() -> ! { panic_display(&"explicit panic"); } @@ -249,7 +256,8 @@ pub fn unreachable_display<T: fmt::Display>(x: &T) -> ! { #[inline] #[track_caller] #[rustc_diagnostic_item = "panic_str_2015"] -#[rustc_const_unstable(feature = "panic_internals", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable pub const fn panic_str_2015(expr: &str) -> ! { panic_display(&expr); } @@ -259,7 +267,8 @@ pub const fn panic_str_2015(expr: &str) -> ! { #[rustc_do_not_const_check] // hooked by const-eval // enforce a &&str argument in const-check and hook this by const-eval #[rustc_const_panic_str] -#[rustc_const_unstable(feature = "panic_internals", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable pub const fn panic_display<T: fmt::Display>(x: &T) -> ! { panic_fmt(format_args!("{}", *x)); } @@ -327,8 +336,9 @@ fn panic_in_cleanup() -> ! { } /// This function is used instead of panic_fmt in const eval. -#[lang = "const_panic_fmt"] -#[rustc_const_unstable(feature = "panic_internals", issue = "none")] +#[lang = "const_panic_fmt"] // needed by const-eval machine to replace calls to `panic_fmt` lang item +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! { if let Some(msg) = fmt.as_str() { // The panic_display function is hooked by const eval. diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 95fa6c9c950..bf9bfd84b56 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -100,7 +100,7 @@ mod prim_bool {} /// /// Both match arms must produce values of type [`u32`], but since `break` never produces a value /// at all we know it can never produce a value which isn't a [`u32`]. This illustrates another -/// behaviour of the `!` type - expressions with type `!` will coerce into any other type. +/// behavior of the `!` type - expressions with type `!` will coerce into any other type. /// /// [`u32`]: prim@u32 /// [`exit`]: ../std/process/fn.exit.html @@ -134,7 +134,7 @@ mod prim_bool {} /// /// Since the [`Err`] variant contains a `!`, it can never occur. If the `exhaustive_patterns` /// feature is present this means we can exhaustively match on [`Result<T, !>`] by just taking the -/// [`Ok`] variant. This illustrates another behaviour of `!` - it can be used to "delete" certain +/// [`Ok`] variant. This illustrates another behavior of `!` - it can be used to "delete" certain /// enum variants from generic types like `Result`. /// /// ## Infinite loops @@ -351,7 +351,7 @@ mod prim_never {} /// ``` /// /// ```no_run -/// // Undefined behaviour +/// // Undefined behavior /// let _ = unsafe { char::from_u32_unchecked(0x110000) }; /// ``` /// @@ -568,7 +568,7 @@ impl () {} /// Instead of coercing a reference to a raw pointer, you can use the macros /// [`ptr::addr_of!`] (for `*const T`) and [`ptr::addr_of_mut!`] (for `*mut T`). /// These macros allow you to create raw pointers to fields to which you cannot -/// create a reference (without causing undefined behaviour), such as an +/// create a reference (without causing undefined behavior), such as an /// unaligned field. This might be necessary if packed structs or uninitialized /// memory is involved. /// @@ -1453,7 +1453,7 @@ mod prim_usize {} /// <code>&[bool]</code> can only point to an allocation containing the integer values `1` /// ([`true`](../std/keyword.true.html)) or `0` ([`false`](../std/keyword.false.html)), but /// creating a <code>&[bool]</code> that points to an allocation containing -/// the value `3` causes undefined behaviour. +/// the value `3` causes undefined behavior. /// In fact, <code>[Option]\<&T></code> has the same memory representation as a /// nullable but aligned pointer, and can be passed across FFI boundaries as such. /// diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index 50706fca5b0..2538d60a8ee 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -41,7 +41,7 @@ impl Alignment { /// This provides the same numerical value as [`mem::align_of`], /// but in an `Alignment` instead of a `usize`. #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const fn of<T>() -> Self { // SAFETY: rustc ensures that type alignment is always a power of two. @@ -53,7 +53,7 @@ impl Alignment { /// /// Note that `0` is not a power of two, nor a valid alignment. #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const fn new(align: usize) -> Option<Self> { if align.is_power_of_two() { @@ -73,7 +73,7 @@ impl Alignment { /// Equivalently, it must be `1 << exp` for some `exp` in `0..usize::BITS`. /// It must *not* be zero. #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const unsafe fn new_unchecked(align: usize) -> Self { assert_unsafe_precondition!( @@ -89,7 +89,7 @@ impl Alignment { /// Returns the alignment as a [`usize`]. #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const fn as_usize(self) -> usize { self.0 as usize @@ -97,7 +97,7 @@ impl Alignment { /// Returns the alignment as a <code>[NonZero]<[usize]></code>. #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const fn as_nonzero(self) -> NonZero<usize> { // SAFETY: All the discriminants are non-zero. @@ -118,7 +118,7 @@ impl Alignment { /// assert_eq!(Alignment::new(1024).unwrap().log2(), 10); /// ``` #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const fn log2(self) -> u32 { self.as_nonzero().trailing_zeros() @@ -148,7 +148,7 @@ impl Alignment { /// assert_ne!(one.mask(Alignment::of::<Align4>().mask()), one); /// ``` #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const fn mask(self) -> usize { // SAFETY: The alignment is always nonzero, and therefore decrementing won't overflow. diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index facf38894d3..75d681d76df 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -39,6 +39,7 @@ impl<T: ?Sized> *const T { } #[inline] + #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] const fn const_impl(ptr: *const u8) -> bool { match (ptr).guaranteed_eq(null_mut()) { Some(res) => res, @@ -113,7 +114,7 @@ impl<T: ?Sized> *const T { /// println!("{:?}", unsafe { &*bad }); /// ``` #[unstable(feature = "set_ptr_value", issue = "75091")] - #[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] #[must_use = "returns a new pointer rather than modifying its argument"] #[inline] pub const fn with_metadata_of<U>(self, meta: *const U) -> *const U @@ -409,6 +410,7 @@ impl<T: ?Sized> *const T { T: Sized, { #[inline] + #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool { #[inline] fn runtime(this: *const (), count: isize, size: usize) -> bool { @@ -761,6 +763,7 @@ impl<T: ?Sized> *const T { where T: Sized, { + #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_ptr_ge(this: *const (), origin: *const ()) -> bool { fn runtime(this: *const (), origin: *const ()) -> bool { this >= origin @@ -902,6 +905,7 @@ impl<T: ?Sized> *const T { { #[cfg(debug_assertions)] #[inline] + #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool { #[inline] fn runtime(this: *const (), count: usize, size: usize) -> bool { @@ -1010,6 +1014,7 @@ impl<T: ?Sized> *const T { { #[cfg(debug_assertions)] #[inline] + #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool { #[inline] fn runtime(this: *const (), count: usize, size: usize) -> bool { @@ -1622,6 +1627,7 @@ impl<T: ?Sized> *const T { } #[inline] + #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] const fn const_impl(ptr: *const (), align: usize) -> bool { // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead. ptr.align_offset(align) == 0 diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 09c4002dbc7..5f20cb2ee72 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -92,7 +92,7 @@ pub trait Thin = Pointee<Metadata = ()>; /// /// assert_eq!(std::ptr::metadata("foo"), 3_usize); /// ``` -#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] #[inline] pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata { ptr_metadata(ptr) @@ -106,7 +106,7 @@ pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata { /// /// [`slice::from_raw_parts`]: crate::slice::from_raw_parts #[unstable(feature = "ptr_metadata", issue = "81513")] -#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] #[inline] pub const fn from_raw_parts<T: ?Sized>( data_pointer: *const impl Thin, @@ -120,7 +120,7 @@ pub const fn from_raw_parts<T: ?Sized>( /// /// See the documentation of [`from_raw_parts`] for more details. #[unstable(feature = "ptr_metadata", issue = "81513")] -#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] #[inline] pub const fn from_raw_parts_mut<T: ?Sized>( data_pointer: *mut impl Thin, diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 03cab232742..e9f5bf4404e 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -134,7 +134,7 @@ //! # Provenance //! //! Pointers are not *simply* an "integer" or "address". For instance, it's uncontroversial -//! to say that a Use After Free is clearly Undefined Behaviour, even if you "get lucky" +//! to say that a Use After Free is clearly Undefined Behavior, even if you "get lucky" //! and the freed memory gets reallocated before your read/write (in fact this is the //! worst-case scenario, UAFs would be much less concerning if this didn't happen!). //! As another example, consider that [`wrapping_offset`] is documented to "remember" @@ -591,8 +591,8 @@ pub const fn null_mut<T: ?Sized + Thin>() -> *mut T { /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[inline(always)] #[must_use] -#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")] #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub const fn without_provenance<T>(addr: usize) -> *const T { // An int-to-pointer transmute currently has exactly the intended semantics: it creates a // pointer without provenance. Note that this is *not* a stable guarantee about transmute @@ -613,8 +613,8 @@ pub const fn without_provenance<T>(addr: usize) -> *const T { /// some other means. #[inline(always)] #[must_use] -#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")] #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub const fn dangling<T>() -> *const T { without_provenance(mem::align_of::<T>()) } @@ -634,8 +634,8 @@ pub const fn dangling<T>() -> *const T { /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[inline(always)] #[must_use] -#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")] #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub const fn without_provenance_mut<T>(addr: usize) -> *mut T { // An int-to-pointer transmute currently has exactly the intended semantics: it creates a // pointer without provenance. Note that this is *not* a stable guarantee about transmute @@ -656,8 +656,8 @@ pub const fn without_provenance_mut<T>(addr: usize) -> *mut T { /// some other means. #[inline(always)] #[must_use] -#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")] #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub const fn dangling_mut<T>() -> *mut T { without_provenance_mut(mem::align_of::<T>()) } @@ -1125,7 +1125,7 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) { unsafe { swap_nonoverlapping_simple_untyped(x, y, count) } } -/// Same behaviour and safety conditions as [`swap_nonoverlapping`] +/// Same behavior and safety conditions as [`swap_nonoverlapping`] /// /// LLVM can vectorize this (at least it can for the power-of-two-sized types /// `swap_nonoverlapping` tries to use) so no need to manually SIMD it. @@ -1854,6 +1854,7 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) { /// Any questions go to @nagisa. #[allow(ptr_to_integer_transmute_in_consts)] #[lang = "align_offset"] +#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize { // FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <= // 1, where the method versions of these operations are not inlined. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 031939cf0d5..408e722267a 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -94,7 +94,7 @@ impl<T: ?Sized> *mut T { /// // This dereference is UB. The pointer only has provenance for `x` but points to `y`. /// println!("{:?}", unsafe { &*bad }); #[unstable(feature = "set_ptr_value", issue = "75091")] - #[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] #[must_use = "returns a new pointer rather than modifying its argument"] #[inline] pub const fn with_metadata_of<U>(self, meta: *const U) -> *mut U @@ -405,6 +405,7 @@ impl<T: ?Sized> *mut T { T: Sized, { #[inline] + #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool { #[inline] fn runtime(this: *const (), count: isize, size: usize) -> bool { @@ -984,6 +985,7 @@ impl<T: ?Sized> *mut T { { #[cfg(debug_assertions)] #[inline] + #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool { #[inline] fn runtime(this: *const (), count: usize, size: usize) -> bool { @@ -1092,6 +1094,7 @@ impl<T: ?Sized> *mut T { { #[cfg(debug_assertions)] #[inline] + #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool { #[inline] fn runtime(this: *const (), count: usize, size: usize) -> bool { @@ -1871,6 +1874,7 @@ impl<T: ?Sized> *mut T { } #[inline] + #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] const fn const_impl(ptr: *mut (), align: usize) -> bool { // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead. ptr.align_offset(align) == 0 diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index d80e1e700aa..86ef1f3f005 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1508,7 +1508,6 @@ impl<T> NonNull<[T]> { #[inline] #[must_use] #[unstable(feature = "slice_ptr_get", issue = "74265")] - #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")] pub const fn as_non_null_ptr(self) -> NonNull<T> { self.cast() } diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs index 4810ebe01f9..a796820a7e4 100644 --- a/library/core/src/ptr/unique.rs +++ b/library/core/src/ptr/unique.rs @@ -92,6 +92,7 @@ impl<T: ?Sized> Unique<T> { /// Creates a new `Unique` if `ptr` is non-null. #[inline] + #[rustc_const_unstable(feature = "ptr_internals", issue = "none")] pub const fn new(ptr: *mut T) -> Option<Self> { if let Some(pointer) = NonNull::new(ptr) { Some(Unique { pointer, _marker: PhantomData }) diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index a03e9fbae11..21e0460072f 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -346,6 +346,8 @@ pub const fn is_ascii_simple(mut bytes: &[u8]) -> bool { /// If any of these loads produces something for which `contains_nonascii` /// (above) returns true, then we know the answer is false. #[inline] +#[rustc_allow_const_fn_unstable(const_raw_ptr_comparison, const_pointer_is_aligned)] // only in a debug assertion +#[rustc_allow_const_fn_unstable(const_align_offset)] // behavior does not change when `align_offset` fails const fn is_ascii(s: &[u8]) -> bool { const USIZE_SIZE: usize = mem::size_of::<usize>(); diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index bc8571c8503..231ab7396ad 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -31,6 +31,7 @@ where #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] +#[rustc_allow_const_fn_unstable(const_eval_select)] const fn slice_start_index_len_fail(index: usize, len: usize) -> ! { // FIXME(const-hack): once integer formatting in panics is possible, we // should use the same implementation at compiletime and runtime. @@ -52,6 +53,7 @@ const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! { #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] +#[rustc_allow_const_fn_unstable(const_eval_select)] const fn slice_end_index_len_fail(index: usize, len: usize) -> ! { // FIXME(const-hack): once integer formatting in panics is possible, we // should use the same implementation at compiletime and runtime. @@ -73,6 +75,7 @@ const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! { #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] +#[rustc_allow_const_fn_unstable(const_eval_select)] const fn slice_index_order_fail(index: usize, end: usize) -> ! { // FIXME(const-hack): once integer formatting in panics is possible, we // should use the same implementation at compiletime and runtime. @@ -310,7 +313,6 @@ unsafe impl<T> SliceIndex<[T]> for usize { /// Because `IndexRange` guarantees `start <= end`, fewer checks are needed here /// than there are for a general `Range<usize>` (which might be `100..3`). -#[rustc_const_unstable(feature = "const_index_range_slice_index", issue = "none")] unsafe impl<T> SliceIndex<[T]> for ops::IndexRange { type Output = [T]; diff --git a/library/core/src/slice/memchr.rs b/library/core/src/slice/memchr.rs index be19c3d3bc1..57604623262 100644 --- a/library/core/src/slice/memchr.rs +++ b/library/core/src/slice/memchr.rs @@ -15,7 +15,7 @@ const USIZE_BYTES: usize = mem::size_of::<usize>(); /// bytes where the borrow propagated all the way to the most significant /// bit." #[inline] -#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))] const fn contains_zero_byte(x: usize) -> bool { x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0 } @@ -23,7 +23,7 @@ const fn contains_zero_byte(x: usize) -> bool { /// Returns the first index matching the byte `x` in `text`. #[inline] #[must_use] -#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))] pub const fn memchr(x: u8, text: &[u8]) -> Option<usize> { // Fast path for small slices. if text.len() < 2 * USIZE_BYTES { @@ -34,7 +34,7 @@ pub const fn memchr(x: u8, text: &[u8]) -> Option<usize> { } #[inline] -#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))] const fn memchr_naive(x: u8, text: &[u8]) -> Option<usize> { let mut i = 0; @@ -52,7 +52,7 @@ const fn memchr_naive(x: u8, text: &[u8]) -> Option<usize> { #[rustc_allow_const_fn_unstable(const_cmp)] #[rustc_allow_const_fn_unstable(const_align_offset)] -#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))] const fn memchr_aligned(x: u8, text: &[u8]) -> Option<usize> { // Scan for a single byte value by reading two `usize` words at a time. // diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index dbcfe946440..27e51afa800 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1265,6 +1265,7 @@ impl<T> [T] { /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] + #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[must_use] pub const unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]] { @@ -1310,6 +1311,7 @@ impl<T> [T] { /// assert_eq!(chunks, &[['R', 'u'], ['s', 't']]); /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] + #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[track_caller] #[must_use] @@ -1344,6 +1346,7 @@ impl<T> [T] { /// assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]); /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] + #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[track_caller] #[must_use] @@ -1422,6 +1425,7 @@ impl<T> [T] { /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_mut() // Zero-length chunks are never allowed /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] + #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[must_use] pub const unsafe fn as_chunks_unchecked_mut<const N: usize>(&mut self) -> &mut [[T; N]] { @@ -1462,6 +1466,7 @@ impl<T> [T] { /// assert_eq!(v, &[1, 1, 2, 2, 9]); /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] + #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[track_caller] #[must_use] @@ -1502,6 +1507,7 @@ impl<T> [T] { /// assert_eq!(v, &[9, 1, 1, 2, 2]); /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] + #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[track_caller] #[must_use] diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index f68465c9bda..665c9fc67d0 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -57,9 +57,9 @@ use crate::{cmp, fmt}; /// [`Searcher`] type, which does the actual work of finding /// occurrences of the pattern in a string. /// -/// Depending on the type of the pattern, the behaviour of methods like +/// Depending on the type of the pattern, the behavior of methods like /// [`str::find`] and [`str::contains`] can change. The table below describes -/// some of those behaviours. +/// some of those behaviors. /// /// | Pattern type | Match condition | /// |--------------------------|-------------------------------------------| diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 17ba18c2a66..93b4ad5c1c9 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -2122,7 +2122,8 @@ macro_rules! atomic_int { $stable_access:meta, $stable_from:meta, $stable_nand:meta, - $const_stable:meta, + $const_stable_new:meta, + $const_stable_into_inner:meta, $diagnostic_item:meta, $s_int_type:literal, $extra_feature:expr, @@ -2204,7 +2205,7 @@ macro_rules! atomic_int { /// ``` #[inline] #[$stable] - #[$const_stable] + #[$const_stable_new] #[must_use] pub const fn new(v: $int_type) -> Self { Self {v: UnsafeCell::new(v)} @@ -2406,7 +2407,7 @@ macro_rules! atomic_int { /// ``` #[inline] #[$stable_access] - #[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")] + #[$const_stable_into_inner] pub const fn into_inner(self) -> $int_type { self.v.into_inner() } @@ -3054,6 +3055,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicI8"), "i8", "", @@ -3072,6 +3074,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicU8"), "u8", "", @@ -3090,6 +3093,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicI16"), "i16", "", @@ -3108,6 +3112,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicU16"), "u16", "", @@ -3126,6 +3131,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicI32"), "i32", "", @@ -3144,6 +3150,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicU32"), "u32", "", @@ -3162,6 +3169,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicI64"), "i64", "", @@ -3180,6 +3188,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicU64"), "u64", "", @@ -3197,7 +3206,8 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "99069"), unstable(feature = "integer_atomics", issue = "99069"), unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_unstable(feature = "integer_atomics", issue = "99069"), + rustc_const_unstable(feature = "integer_atomics", issue = "99069"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"), "i128", "#![feature(integer_atomics)]\n\n", @@ -3215,7 +3225,8 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "99069"), unstable(feature = "integer_atomics", issue = "99069"), unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_unstable(feature = "integer_atomics", issue = "99069"), + rustc_const_unstable(feature = "integer_atomics", issue = "99069"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"), "u128", "#![feature(integer_atomics)]\n\n", @@ -3238,6 +3249,7 @@ macro_rules! atomic_int_ptr_sized { stable(feature = "atomic_from", since = "1.23.0"), stable(feature = "atomic_nand", since = "1.27.0"), rustc_const_stable(feature = "const_ptr_sized_atomics", since = "1.24.0"), + rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicIsize"), "isize", "", @@ -3256,6 +3268,7 @@ macro_rules! atomic_int_ptr_sized { stable(feature = "atomic_from", since = "1.23.0"), stable(feature = "atomic_nand", since = "1.27.0"), rustc_const_stable(feature = "const_ptr_sized_atomics", since = "1.24.0"), + rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicUsize"), "usize", "", diff --git a/library/core/src/sync/exclusive.rs b/library/core/src/sync/exclusive.rs index fbf8dafad18..af25f139739 100644 --- a/library/core/src/sync/exclusive.rs +++ b/library/core/src/sync/exclusive.rs @@ -106,6 +106,7 @@ impl<T: Sized> Exclusive<T> { /// Unwrap the value contained in the `Exclusive` #[unstable(feature = "exclusive_wrapper", issue = "98407")] + #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] #[inline] pub const fn into_inner(self) -> T { @@ -129,6 +130,7 @@ impl<T: ?Sized> Exclusive<T> { /// access to the underlying value, but _pinned_ `Exclusive`s only /// produce _pinned_ access to the underlying value. #[unstable(feature = "exclusive_wrapper", issue = "98407")] + #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] #[inline] pub const fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> { @@ -152,6 +154,7 @@ impl<T: ?Sized> Exclusive<T> { /// a _pinned mutable_ reference to a `T`. This allows you to skip /// building an `Exclusive` with [`Exclusive::new`]. #[unstable(feature = "exclusive_wrapper", issue = "98407")] + #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] #[inline] pub const fn from_pin_mut(r: Pin<&'_ mut T>) -> Pin<&'_ mut Exclusive<T>> { diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 3e795e7b5e3..fb7af8234dd 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -321,7 +321,7 @@ impl<'a> ContextBuilder<'a> { /// Creates a ContextBuilder from a Waker. #[inline] #[unstable(feature = "local_waker", issue = "118959")] - #[rustc_const_stable(feature = "const_waker", since = "1.82.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_waker", since = "1.82.0"))] pub const fn from_waker(waker: &'a Waker) -> Self { // SAFETY: LocalWaker is just Waker without thread safety let local_waker = unsafe { transmute(waker) }; @@ -379,7 +379,7 @@ impl<'a> ContextBuilder<'a> { /// Builds the `Context`. #[inline] #[unstable(feature = "local_waker", issue = "118959")] - #[rustc_const_stable(feature = "const_waker", since = "1.82.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_waker", since = "1.82.0"))] pub const fn build(self) -> Context<'a> { let ContextBuilder { waker, local_waker, ext, _marker, _marker2 } = self; Context { waker, local_waker, ext: AssertUnwindSafe(ext), _marker, _marker2 } diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs index daaaf5a7195..91566439ade 100644 --- a/library/core/src/ub_checks.rs +++ b/library/core/src/ub_checks.rs @@ -47,7 +47,7 @@ use crate::intrinsics::{self, const_eval_select}; /// order to call it. Since the precompiled standard library is built with full debuginfo and these /// variables cannot be optimized out in MIR, an innocent-looking `let` can produce enough /// debuginfo to have a measurable compile-time impact on debug builds. -#[allow_internal_unstable(const_ub_checks)] // permit this to be called in stably-const fn +#[cfg_attr(bootstrap, allow_internal_unstable(const_ub_checks))] // permit this to be called in stably-const fn #[macro_export] #[unstable(feature = "ub_checks", issue = "none")] macro_rules! assert_unsafe_precondition { @@ -64,7 +64,8 @@ macro_rules! assert_unsafe_precondition { #[rustc_no_mir_inline] #[inline] #[rustc_nounwind] - #[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))] + #[rustc_allow_const_fn_unstable(const_ptr_is_null, const_ub_checks)] // only for UB checks const fn precondition_check($($name:$ty),*) { if !$e { ::core::panicking::panic_nounwind( @@ -90,8 +91,9 @@ pub use intrinsics::ub_checks as check_library_ub; /// /// The intention is to not do that when running in the interpreter, as that one has its own /// language UB checks which generally produce better errors. -#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))] #[inline] +#[rustc_allow_const_fn_unstable(const_eval_select)] pub(crate) const fn check_language_ub() -> bool { #[inline] fn runtime() -> bool { @@ -116,6 +118,7 @@ pub(crate) const fn check_language_ub() -> bool { /// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the /// check is anyway not executed in `const`. #[inline] +#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] pub(crate) const fn is_aligned_and_not_null(ptr: *const (), align: usize, is_zst: bool) -> bool { ptr.is_aligned_to(align) && (is_zst || !ptr.is_null()) } @@ -132,6 +135,7 @@ pub(crate) const fn is_valid_allocation_size(size: usize, len: usize) -> bool { /// Note that in const-eval this function just returns `true` and therefore must /// only be used with `assert_unsafe_precondition!`, similar to `is_aligned_and_not_null`. #[inline] +#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] pub(crate) const fn is_nonoverlapping( src: *const (), dst: *const (), diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 14603aa30e8..8c898718865 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -22,7 +22,6 @@ #![feature(const_eval_select)] #![feature(const_hash)] #![feature(const_heap)] -#![feature(const_likely)] #![feature(const_nonnull_new)] #![feature(const_num_midpoint)] #![feature(const_option_ext)] diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index 7d3381ee504..1608080d6b6 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -113,7 +113,7 @@ macro_rules! int_module { // Rotating these should make no difference // // We test using 124 bits because to ensure that overlong bit shifts do - // not cause undefined behaviour. See #10183. + // not cause undefined behavior. See #10183. assert_eq_const_safe!(_0.rotate_left(124), _0); assert_eq_const_safe!(_1.rotate_left(124), _1); assert_eq_const_safe!(_0.rotate_right(124), _0); diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs index 105aad4522d..ad8e48491e8 100644 --- a/library/core/tests/num/uint_macros.rs +++ b/library/core/tests/num/uint_macros.rs @@ -79,7 +79,7 @@ macro_rules! uint_module { // Rotating these should make no difference // // We test using 124 bits because to ensure that overlong bit shifts do - // not cause undefined behaviour. See #10183. + // not cause undefined behavior. See #10183. assert_eq_const_safe!(_0.rotate_left(124), _0); assert_eq_const_safe!(_1.rotate_left(124), _1); assert_eq_const_safe!(_0.rotate_right(124), _0); diff --git a/library/proc_macro/src/bridge/symbol.rs b/library/proc_macro/src/bridge/symbol.rs index 37aaee6b215..edad6e7ac39 100644 --- a/library/proc_macro/src/bridge/symbol.rs +++ b/library/proc_macro/src/bridge/symbol.rs @@ -76,7 +76,7 @@ impl Symbol { .all(|b| matches!(b, b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9')) } - // Mimics the behaviour of `Symbol::can_be_raw` from `rustc_span` + // Mimics the behavior of `Symbol::can_be_raw` from `rustc_span` fn can_be_raw(string: &str) -> bool { match string { "_" | "super" | "self" | "Self" | "crate" => false, diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs index fa8ea95b891..b79ad1c3119 100644 --- a/library/std/src/collections/hash/map/tests.rs +++ b/library/std/src/collections/hash/map/tests.rs @@ -1098,7 +1098,7 @@ mod test_extract_if { _ => panic!(), }); catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err(); - // Iterator behaviour after a panic is explicitly unspecified, + // Iterator behavior after a panic is explicitly unspecified, // so this is just the current implementation: let result = catch_unwind(AssertUnwindSafe(|| it.next())); assert!(result.is_err()); diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 97a1b846a91..d732a15117e 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -618,7 +618,7 @@ impl Error for JoinPathsError { /// /// # Deprecation /// -/// This function is deprecated because the behaviour on Windows is not correct. +/// This function is deprecated because the behavior on Windows is not correct. /// The 'HOME' environment variable is not standard on Windows, and may not produce /// desired results; for instance, under Cygwin or Mingw it will return `/home/you` /// when it should return `C:\Users\you`. diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index a964db2e0ac..ba6481f052c 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -153,7 +153,7 @@ pub trait FileExt { /// /// It is possible to inadvertently set this flag, like in the example below. /// Therefore, it is important to be vigilant while changing options to mitigate - /// unexpected behaviour. + /// unexpected behavior. /// /// ```no_run /// use std::fs::File; diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 63edfdb82f3..62125f885b2 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1167,7 +1167,7 @@ impl FusedIterator for Ancestors<'_> {} /// path.push(r"..\otherdir"); /// path.push("system32"); /// -/// The behaviour of `PathBuf` may be changed to a panic on such inputs +/// The behavior of `PathBuf` may be changed to a panic on such inputs /// in the future. [`Extend::extend`] should be used to add multi-part paths. #[cfg_attr(not(test), rustc_diagnostic_item = "PathBuf")] #[stable(feature = "rust1", since = "1.0.0")] @@ -1409,7 +1409,7 @@ impl PathBuf { /// (That is, it will have the same parent.) /// /// The argument is not sanitized, so can include separators. This - /// behaviour may be changed to a panic in the future. + /// behavior may be changed to a panic in the future. /// /// [`self.file_name`]: Path::file_name /// [`pop`]: PathBuf::pop diff --git a/library/std/src/process.rs b/library/std/src/process.rs index f24fe353e55..6933528cdbd 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -119,7 +119,7 @@ //! when given a `.bat` file as the application to run, it will automatically //! convert that into running `cmd.exe /c` with the batch file as the next argument. //! -//! For historical reasons Rust currently preserves this behaviour when using +//! For historical reasons Rust currently preserves this behavior when using //! [`Command::new`], and escapes the arguments according to `cmd.exe` rules. //! Due to the complexity of `cmd.exe` argument handling, it might not be //! possible to safely escape some special characters, and using them will result @@ -2318,7 +2318,7 @@ pub fn exit(code: i32) -> ! { /// Rust IO buffers (eg, from `BufWriter`) will not be flushed. /// Likewise, C stdio buffers will (on most platforms) not be flushed. /// -/// This is in contrast to the default behaviour of [`panic!`] which unwinds +/// This is in contrast to the default behavior of [`panic!`] which unwinds /// the current thread's stack and calls all destructors. /// When `panic="abort"` is set, either as an argument to `rustc` or in a /// crate's Cargo.toml, [`panic!`] and `abort` are similar. However, diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs index 34acd9c9a94..2c8ba411f30 100644 --- a/library/std/src/sync/mpmc/array.rs +++ b/library/std/src/sync/mpmc/array.rs @@ -484,7 +484,7 @@ impl<T> Channel<T> { /// /// # Panicking /// If a destructor panics, the remaining messages are leaked, matching the - /// behaviour of the unbounded channel. + /// behavior of the unbounded channel. /// /// # Safety /// This method must only be called when dropping the last receiver. The diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index 993df9314fc..27db4b634fb 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -288,7 +288,7 @@ impl Once { /// /// If this [`Once`] has been poisoned because an initialization closure has /// panicked, this method will also panic. Use [`wait_force`](Self::wait_force) - /// if this behaviour is not desired. + /// if this behavior is not desired. #[unstable(feature = "once_wait", issue = "127527")] pub fn wait(&self) { if !self.inner.is_completed() { diff --git a/library/std/src/sys/pal/unix/process/process_fuchsia.rs b/library/std/src/sys/pal/unix/process/process_fuchsia.rs index 5d0110cf55d..8f7d786e32f 100644 --- a/library/std/src/sys/pal/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/pal/unix/process/process_fuchsia.rs @@ -273,7 +273,7 @@ impl ExitStatus { // We don't know what someone who calls into_raw() will do with this value, but it should // have the conventional Unix representation. Despite the fact that this is not // standardised in SuS or POSIX, all Unix systems encode the signal and exit status the - // same way. (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behaviour on every + // same way. (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behavior on every // Unix.) // // The caller of `std::os::unix::into_raw` is probably wanting a Unix exit status, and may diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index b237fa481e2..5a9bfccc1fa 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -1159,7 +1159,7 @@ pub fn symlink_inner(original: &Path, link: &Path, dir: bool) -> io::Result<()> // Formerly, symlink creation required the SeCreateSymbolicLink privilege. For the Windows 10 // Creators Update, Microsoft loosened this to allow unprivileged symlink creation if the // computer is in Developer Mode, but SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE must be - // added to dwFlags to opt into this behaviour. + // added to dwFlags to opt into this behavior. let result = cvt(unsafe { c::CreateSymbolicLinkW( link.as_ptr(), diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs index 95b51e704f9..17bb03fe7af 100644 --- a/library/std/src/sys/pal/windows/process.rs +++ b/library/std/src/sys/pal/windows/process.rs @@ -47,7 +47,7 @@ impl EnvKey { } } -// Comparing Windows environment variable keys[1] are behaviourally the +// Comparing Windows environment variable keys[1] are behaviorally the // composition of two operations[2]: // // 1. Case-fold both strings. This is done using a language-independent @@ -338,8 +338,8 @@ impl Command { // If at least one of stdin, stdout or stderr are set (i.e. are non null) // then set the `hStd` fields in `STARTUPINFO`. - // Otherwise skip this and allow the OS to apply its default behaviour. - // This provides more consistent behaviour between Win7 and Win8+. + // Otherwise skip this and allow the OS to apply its default behavior. + // This provides more consistent behavior between Win7 and Win8+. let is_set = |stdio: &Handle| !stdio.as_raw_handle().is_null(); if is_set(&stderr) || is_set(&stdout) || is_set(&stdin) { si.dwFlags |= c::STARTF_USESTDHANDLES; @@ -507,7 +507,7 @@ where Exists: FnMut(PathBuf) -> Option<Vec<u16>>, { // 1. Child paths - // This is for consistency with Rust's historic behaviour. + // This is for consistency with Rust's historic behavior. if let Some(paths) = child_paths { for path in env::split_paths(paths).filter(|p| !p.as_os_str().is_empty()) { if let Some(path) = exists(path) { diff --git a/library/std/src/sys/pal/windows/process/tests.rs b/library/std/src/sys/pal/windows/process/tests.rs index b567151b721..1bcc5fa6b20 100644 --- a/library/std/src/sys/pal/windows/process/tests.rs +++ b/library/std/src/sys/pal/windows/process/tests.rs @@ -191,7 +191,7 @@ fn windows_exe_resolver() { /* Some of the following tests may need to be changed if you are deliberately - changing the behaviour of `resolve_exe`. + changing the behavior of `resolve_exe`. */ let empty_paths = || None; diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs index 28bce529cd9..2c8ce42f414 100644 --- a/library/std/src/sys/pal/windows/thread.rs +++ b/library/std/src/sys/pal/windows/thread.rs @@ -99,7 +99,7 @@ impl Thread { } // Attempt to use high-precision sleep (Windows 10, version 1803+). // On error fallback to the standard `Sleep` function. - // Also preserves the zero duration behaviour of `Sleep`. + // Also preserves the zero duration behavior of `Sleep`. if dur.is_zero() || high_precision_sleep(dur).is_err() { unsafe { c::Sleep(super::dur2timeout(dur)) } } diff --git a/library/std/src/sys/path/windows/tests.rs b/library/std/src/sys/path/windows/tests.rs index 623c6236166..f2a60e30bc6 100644 --- a/library/std/src/sys/path/windows/tests.rs +++ b/library/std/src/sys/path/windows/tests.rs @@ -119,7 +119,7 @@ fn test_windows_prefix_components() { /// See #101358. /// -/// Note that the exact behaviour here may change in the future. +/// Note that the exact behavior here may change in the future. /// In which case this test will need to adjusted. #[test] fn broken_unc_path() { diff --git a/library/std/src/sys/random/linux.rs b/library/std/src/sys/random/linux.rs index 073fdc45e61..e3cb79285cd 100644 --- a/library/std/src/sys/random/linux.rs +++ b/library/std/src/sys/random/linux.rs @@ -30,7 +30,7 @@ //! data the system has available at the time. //! //! So in conclusion, we always want the output of the non-blocking pool, but -//! may need to wait until it is initalized. The default behaviour of `getrandom` +//! may need to wait until it is initalized. The default behavior of `getrandom` //! is to wait until the non-blocking pool is initialized and then draw from there, //! so if `getrandom` is available, we use its default to generate the bytes. For //! `HashMap`, however, we need to specify the `GRND_INSECURE` flags, but that @@ -39,7 +39,7 @@ //! succeed if the pool is initialized. If it isn't, we fall back to the file //! access method. //! -//! The behaviour of `/dev/urandom` is inverse to that of `getrandom`: it always +//! The behavior of `/dev/urandom` is inverse to that of `getrandom`: it always //! yields data, even when the pool is not initialized. For generating `HashMap` //! keys, this is not important, so we can use it directly. For secure data //! however, we need to wait until initialization, which we can do by `poll`ing diff --git a/library/std/src/sys/sync/condvar/pthread.rs b/library/std/src/sys/sync/condvar/pthread.rs index 986cd0cb7d1..cee728e35cd 100644 --- a/library/std/src/sys/sync/condvar/pthread.rs +++ b/library/std/src/sys/sync/condvar/pthread.rs @@ -66,7 +66,7 @@ impl Drop for AllocatedCondvar { // On DragonFly pthread_cond_destroy() returns EINVAL if called on // a condvar that was just initialized with // libc::PTHREAD_COND_INITIALIZER. Once it is used or - // pthread_cond_init() is called, this behaviour no longer occurs. + // pthread_cond_init() is called, this behavior no longer occurs. debug_assert!(r == 0 || r == libc::EINVAL); } else { debug_assert_eq!(r, 0); diff --git a/library/std/src/sys/sync/mutex/pthread.rs b/library/std/src/sys/sync/mutex/pthread.rs index 87c95f45f96..abd58122523 100644 --- a/library/std/src/sys/sync/mutex/pthread.rs +++ b/library/std/src/sys/sync/mutex/pthread.rs @@ -65,7 +65,7 @@ impl Drop for AllocatedMutex { // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER. // Once it is used (locked/unlocked) or pthread_mutex_init() is called, - // this behaviour no longer occurs. + // this behavior no longer occurs. debug_assert!(r == 0 || r == libc::EINVAL); } else { debug_assert_eq!(r, 0); @@ -88,7 +88,7 @@ impl Mutex { /// since the `lock` and the lock must have occurred on the current thread. /// /// # Safety - /// Causes undefined behaviour if the mutex is not locked. + /// Causes undefined behavior if the mutex is not locked. #[inline] pub(crate) unsafe fn get_assert_locked(&self) -> *mut libc::pthread_mutex_t { unsafe { self.inner.get_unchecked().0.get() } diff --git a/library/std/src/sys/sync/once/queue.rs b/library/std/src/sys/sync/once/queue.rs index 3e83a4a088f..177d0d7744a 100644 --- a/library/std/src/sys/sync/once/queue.rs +++ b/library/std/src/sys/sync/once/queue.rs @@ -116,7 +116,7 @@ fn to_state(current: StateAndQueue) -> usize { impl Once { #[inline] - #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_once_new", since = "1.32.0"))] pub const fn new() -> Once { Once { state_and_queue: AtomicPtr::new(ptr::without_provenance_mut(INCOMPLETE)) } } diff --git a/library/std/src/sys/sync/once_box.rs b/library/std/src/sys/sync/once_box.rs index 9d24db2245a..4105af50329 100644 --- a/library/std/src/sys/sync/once_box.rs +++ b/library/std/src/sys/sync/once_box.rs @@ -36,7 +36,7 @@ impl<T> OnceBox<T> { /// ``` /// /// # Safety - /// This causes undefined behaviour if the assumption above is violated. + /// This causes undefined behavior if the assumption above is violated. #[inline] pub unsafe fn get_unchecked(&self) -> &T { unsafe { &*self.ptr.load(Relaxed) } diff --git a/library/std/src/sys/sync/rwlock/futex.rs b/library/std/src/sys/sync/rwlock/futex.rs index df22c36dd5a..447048edf76 100644 --- a/library/std/src/sys/sync/rwlock/futex.rs +++ b/library/std/src/sys/sync/rwlock/futex.rs @@ -283,7 +283,7 @@ impl RwLock { futex_wake(&self.writer_notify) // Note that FreeBSD and DragonFlyBSD don't tell us whether they woke // up any threads or not, and always return `false` here. That still - // results in correct behaviour: it just means readers get woken up as + // results in correct behavior: it just means readers get woken up as // well in case both readers and writers were waiting. } diff --git a/library/std/src/sys/sync/rwlock/queue.rs b/library/std/src/sys/sync/rwlock/queue.rs index 733f51cae8c..889961915f4 100644 --- a/library/std/src/sys/sync/rwlock/queue.rs +++ b/library/std/src/sys/sync/rwlock/queue.rs @@ -8,7 +8,7 @@ //! * `pthread` is an external library, meaning the fast path of acquiring an //! uncontended lock cannot be inlined. //! * Some platforms (at least glibc before version 2.25) have buggy implementations -//! that can easily lead to undefined behaviour in safe Rust code when not properly +//! that can easily lead to undefined behavior in safe Rust code when not properly //! guarded against. //! * On some platforms (e.g. macOS), the lock is very slow. //! diff --git a/library/std/src/sys/sync/thread_parking/darwin.rs b/library/std/src/sys/sync/thread_parking/darwin.rs index 96e3d23c332..0553c5e19a9 100644 --- a/library/std/src/sys/sync/thread_parking/darwin.rs +++ b/library/std/src/sys/sync/thread_parking/darwin.rs @@ -5,7 +5,7 @@ //! rejection from the App Store). //! //! Therefore, we need to look for other synchronization primitives. Luckily, Darwin -//! supports semaphores, which allow us to implement the behaviour we need with +//! supports semaphores, which allow us to implement the behavior we need with //! only one primitive (as opposed to a mutex-condvar pair). We use the semaphore //! provided by libdispatch, as the underlying Mach semaphore is only dubiously //! public. diff --git a/library/std/src/sys/sync/thread_parking/pthread.rs b/library/std/src/sys/sync/thread_parking/pthread.rs index 5f195d0bb0c..76df73b2a8e 100644 --- a/library/std/src/sys/sync/thread_parking/pthread.rs +++ b/library/std/src/sys/sync/thread_parking/pthread.rs @@ -97,7 +97,7 @@ impl Parker { /// The constructed parker must never be moved. pub unsafe fn new_in_place(parker: *mut Parker) { // Use the default mutex implementation to allow for simpler initialization. - // This could lead to undefined behaviour when deadlocking. This is avoided + // This could lead to undefined behavior when deadlocking. This is avoided // by not deadlocking. Note in particular the unlocking operation before any // panic, as code after the panic could try to park again. (&raw mut (*parker).state).write(AtomicUsize::new(EMPTY)); diff --git a/library/std/src/sys/sync/thread_parking/windows7.rs b/library/std/src/sys/sync/thread_parking/windows7.rs index 8f7e66c46ef..f7585e882f0 100644 --- a/library/std/src/sys/sync/thread_parking/windows7.rs +++ b/library/std/src/sys/sync/thread_parking/windows7.rs @@ -35,7 +35,7 @@ // different implementations. // // Unfortunately, NT Keyed Events are an undocumented Windows API. However: -// - This API is relatively simple with obvious behaviour, and there are +// - This API is relatively simple with obvious behavior, and there are // several (unofficial) articles documenting the details. [1] // - `parking_lot` has been using this API for years (on Windows versions // before Windows 8). [2] Many big projects extensively use parking_lot, @@ -43,7 +43,7 @@ // - It is the underlying API used by Windows SRW locks and Windows critical // sections. [3] [4] // - The source code of the implementations of Wine, ReactOs, and Windows XP -// are available and match the expected behaviour. +// are available and match the expected behavior. // - The main risk with an undocumented API is that it might change in the // future. But since we only use it for older versions of Windows, that's not // a problem. diff --git a/library/std/src/sys/thread_local/key/racy.rs b/library/std/src/sys/thread_local/key/racy.rs index 69f11458c32..97df8997b80 100644 --- a/library/std/src/sys/thread_local/key/racy.rs +++ b/library/std/src/sys/thread_local/key/racy.rs @@ -30,7 +30,7 @@ const KEY_SENTVAL: usize = 0; const KEY_SENTVAL: usize = libc::PTHREAD_KEYS_MAX + 1; impl LazyKey { - #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "thread_local_internals", issue = "none"))] pub const fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> LazyKey { LazyKey { key: atomic::AtomicUsize::new(KEY_SENTVAL), dtor } } diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs index f5a2aaa6c6a..58f291ffdb9 100644 --- a/library/std/src/sys/thread_local/os.rs +++ b/library/std/src/sys/thread_local/os.rs @@ -60,7 +60,7 @@ struct Value<T: 'static> { } impl<T: 'static> Storage<T> { - #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "thread_local_internals", issue = "none"))] pub const fn new() -> Storage<T> { Storage { key: LazyKey::new(Some(destroy_value::<T>)), marker: PhantomData } } diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 88bf186700f..9edb3fa4193 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -237,7 +237,7 @@ impl<T: 'static> LocalKey<T> { reason = "recently added to create a key", issue = "none" )] - #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "thread_local_internals", issue = "none"))] pub const unsafe fn new(inner: fn(Option<&mut Option<T>>) -> *const T) -> LocalKey<T> { LocalKey { inner } } diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 70aa3170c6e..227ee9d64f3 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -878,7 +878,7 @@ pub fn sleep(dur: Duration) { /// /// # Platform-specific behavior /// -/// This function uses [`sleep`] internally, see its platform-specific behaviour. +/// This function uses [`sleep`] internally, see its platform-specific behavior. /// /// /// # Examples @@ -949,7 +949,7 @@ pub fn sleep_until(deadline: Instant) { } /// Used to ensure that `park` and `park_timeout` do not unwind, as that can -/// cause undefined behaviour if not handled correctly (see #102398 for context). +/// cause undefined behavior if not handled correctly (see #102398 for context). struct PanicGuard; impl Drop for PanicGuard { diff --git a/library/std/src/time.rs b/library/std/src/time.rs index f28a0568a3c..9f4f8a0d088 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -178,9 +178,9 @@ pub struct Instant(time::Instant); /// system. /// /// A `SystemTime` does not count leap seconds. -/// `SystemTime::now()`'s behaviour around a leap second +/// `SystemTime::now()`'s behavior around a leap second /// is the same as the operating system's wall clock. -/// The precise behaviour near a leap second +/// The precise behavior near a leap second /// (e.g. whether the clock appears to run slow or fast, or stop, or jump) /// depends on platform and configuration, /// so should not be relied on. diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py index 1aa9a4a1794..77e2741f9ea 100755 --- a/src/ci/docker/scripts/fuchsia-test-runner.py +++ b/src/ci/docker/scripts/fuchsia-test-runner.py @@ -287,7 +287,7 @@ class TestEnvironment: @property def package_server_log_path(self) -> Path: - return self.tmp_dir().joinpath("package_server_log") + return self.tmp_dir().joinpath(f"repo_{self.TEST_REPO_NAME}.log") @property def emulator_log_path(self) -> Path: @@ -401,6 +401,7 @@ class TestEnvironment: # Set configs configs = { "log.enabled": "true", + "log.dir": self.tmp_dir(), "test.is_isolated": "true", "test.experimental_structured_output": "true", } @@ -575,43 +576,19 @@ class TestEnvironment: stderr_handler=self.subprocess_logger.debug, ) - # Add repository - check_call_with_logging( - [ - ffx_path, - "repository", - "add-from-pm", - "--repository", - self.TEST_REPO_NAME, - self.repo_dir(), - ], - env=ffx_env, - stdout_handler=self.subprocess_logger.debug, - stderr_handler=self.subprocess_logger.debug, - ) - - # Start repository server - # Note that we must first enable the repository server daemon. - check_call_with_logging( - [ - ffx_path, - "config", - "set", - "repository.server.enabled", - "true", - ], - env=ffx_env, - stdout_handler=self.subprocess_logger.debug, - stderr_handler=self.subprocess_logger.debug, - ) check_call_with_logging( [ ffx_path, "repository", "server", "start", + "--background", "--address", "[::]:0", + "--repo-path", + self.repo_dir(), + "--repository", + self.TEST_REPO_NAME ], env=ffx_env, stdout_handler=self.subprocess_logger.debug, @@ -1009,6 +986,21 @@ class TestEnvironment: stderr_handler=self.subprocess_logger.debug, ) + # Stop the package server + self.env_logger.info("Stopping package server...") + check_call_with_logging( + [ + self.tool_path("ffx"), + "repository", + "server", + "stop", + self.TEST_REPO_NAME + ], + env=self.ffx_cmd_env(), + stdout_handler=self.subprocess_logger.debug, + stderr_handler=self.subprocess_logger.debug, + ) + # Stop ffx isolation self.env_logger.info("Stopping ffx isolation...") self.stop_ffx_isolation() diff --git a/src/ci/run.sh b/src/ci/run.sh index 3962c354c10..8e2f525db68 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -47,11 +47,6 @@ source "$ci_dir/shared.sh" export CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse -# suppress change-tracker warnings on CI -if [ "$CI" != "" ]; then - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set change-id=99999999" -fi - # If runner uses an incompatible option and `FORCE_CI_RUSTC` is not defined, # switch to in-tree rustc. if [ "$FORCE_CI_RUSTC" == "" ]; then diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 81264b49dfd..ea349f878e0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1400,7 +1400,6 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo clean_ty_generics(cx, tcx.generics_of(assoc_item.def_id), ty::GenericPredicates { parent: None, predicates, - effects_min_tys: ty::List::empty(), }); simplify::move_bounds_to_generic_parameters(&mut generics); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c8cb9267eb2..c62144be3da 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -8,7 +8,6 @@ use arrayvec::ArrayVec; use rustc_ast::MetaItemInner; use rustc_ast_pretty::pprust; use rustc_attr::{ConstStability, Deprecation, Stability, StableSince}; -use rustc_const_eval::const_eval::is_unstable_const_fn; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; @@ -641,12 +640,11 @@ impl Item { asyncness: ty::Asyncness, ) -> hir::FnHeader { let sig = tcx.fn_sig(def_id).skip_binder(); - let constness = - if tcx.is_const_fn(def_id) || is_unstable_const_fn(tcx, def_id).is_some() { - hir::Constness::Const - } else { - hir::Constness::NotConst - }; + let constness = if tcx.is_const_fn(def_id) { + hir::Constness::Const + } else { + hir::Constness::NotConst + }; let asyncness = match asyncness { ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP), ty::Asyncness::No => hir::IsAsync::NotAsync, @@ -664,9 +662,7 @@ impl Item { safety }, abi, - constness: if tcx.is_const_fn(def_id) - || is_unstable_const_fn(tcx, def_id).is_some() - { + constness: if tcx.is_const_fn(def_id) { hir::Constness::Const } else { hir::Constness::NotConst diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index ce96d1d0a95..8446235fb18 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1010,7 +1010,9 @@ 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 unstable = if let Some(n) = issue + && let Some(feature) = feature + { format!( "<a \ href=\"https://github.com/rust-lang/rust/issues/{n}\" \ diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index cb9b3985bf6..7c9dcd41e6a 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -37,7 +37,6 @@ extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_ast_pretty; extern crate rustc_attr; -extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; diff --git a/src/tools/cargo b/src/tools/cargo -Subproject cf53cc54bb593b5ec3dc2be4b1702f50c36d24d +Subproject e75214ea4936d2f2c909a71a1237042cc0e14b0 diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 82a66cc9202..e8e21edd494 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -324,7 +324,7 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h // If the current self type doesn't implement Copy (due to generic constraints), search to see if // there's a Copy impl for any instance of the adt. if !is_copy(cx, ty) { - if ty_subs.non_erasable_generics(cx.tcx, ty_adt.did()).next().is_some() { + if ty_subs.non_erasable_generics().next().is_some() { let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(©_id).map_or(false, |impls| { impls.iter().any(|&id| { matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _) diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/ident_iter.rs b/src/tools/clippy/clippy_utils/src/ast_utils/ident_iter.rs index 032cd3ed739..22b2c895f7c 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/ident_iter.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/ident_iter.rs @@ -39,7 +39,7 @@ impl From<&Attribute> for IdentIter { struct IdentCollector(Vec<Ident>); impl Visitor<'_> for IdentCollector { - fn visit_ident(&mut self, ident: Ident) { - self.0.push(ident); + fn visit_ident(&mut self, ident: &Ident) { + self.0.push(*ident); } } diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 5f12b6bf99e..46739862de6 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -334,7 +334,7 @@ fn check_terminator<'tcx>( | TerminatorKind::TailCall { func, args, fn_span: _ } => { let fn_ty = func.ty(body, tcx); if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() { - if !is_const_fn(tcx, fn_def_id, msrv) { + if !is_stable_const_fn(tcx, fn_def_id, msrv) { return Err(( span, format!( @@ -377,12 +377,12 @@ fn check_terminator<'tcx>( } } -fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool { +fn is_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool { tcx.is_const_fn(def_id) - && tcx.lookup_const_stability(def_id).map_or(true, |const_stab| { + && tcx.lookup_const_stability(def_id).is_none_or(|const_stab| { if let rustc_attr::StabilityLevel::Stable { since, .. } = const_stab.level { // Checking MSRV is manually necessary because `rustc` has no such concept. This entire - // function could be removed if `rustc` provided a MSRV-aware version of `is_const_fn`. + // function could be removed if `rustc` provided a MSRV-aware version of `is_stable_const_fn`. // as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262. let const_stab_rust_version = match since { @@ -393,8 +393,12 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool { msrv.meets(const_stab_rust_version) } else { - // Unstable const fn with the feature enabled. - msrv.current().is_none() + // 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() } }) } diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index 02931306f16..8db6502dbfb 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -346,13 +346,13 @@ pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> .cx .qpath_res(p, hir_id) .opt_def_id() - .map_or(false, |id| self.cx.tcx.is_const_fn_raw(id)) => {}, + .map_or(false, |id| self.cx.tcx.is_const_fn(id)) => {}, ExprKind::MethodCall(..) if self .cx .typeck_results() .type_dependent_def_id(e.hir_id) - .map_or(false, |id| self.cx.tcx.is_const_fn_raw(id)) => {}, + .map_or(false, |id| self.cx.tcx.is_const_fn(id)) => {}, ExprKind::Binary(_, lhs, rhs) if self.cx.typeck_results().expr_ty(lhs).peel_refs().is_primitive_ty() && self.cx.typeck_results().expr_ty(rhs).peel_refs().is_primitive_ty() => {}, diff --git a/tests/crashes/131342-2.rs b/tests/crashes/131342-2.rs new file mode 100644 index 00000000000..79b6a837a49 --- /dev/null +++ b/tests/crashes/131342-2.rs @@ -0,0 +1,40 @@ +//@ known-bug: #131342 +// see also: 131342.rs + +fn main() { + problem_thingy(Once); +} + +struct Once; + +impl Iterator for Once { + type Item = (); +} + +fn problem_thingy(items: impl Iterator) { + let peeker = items.peekable(); + problem_thingy(&peeker); +} + +trait Iterator { + type Item; + + fn peekable(self) -> Peekable<Self> + where + Self: Sized, + { + loop {} + } +} + +struct Peekable<I: Iterator> { + _peeked: I::Item, +} + +impl<I: Iterator> Iterator for Peekable<I> { + type Item = I::Item; +} + +impl<I: Iterator + ?Sized> Iterator for &I { + type Item = I::Item; +} diff --git a/tests/crashes/131342.rs b/tests/crashes/131342.rs index 266aa0da97d..7f7ee9c9ac1 100644 --- a/tests/crashes/131342.rs +++ b/tests/crashes/131342.rs @@ -1,4 +1,5 @@ //@ known-bug: #131342 +// see also: 131342-2.rs fn main() { let mut items = vec![1, 2, 3, 4, 5].into_iter(); diff --git a/tests/rustdoc/const-display.rs b/tests/rustdoc/const-display.rs index a71825d883d..bc4270c421d 100644 --- a/tests/rustdoc/const-display.rs +++ b/tests/rustdoc/const-display.rs @@ -89,10 +89,4 @@ impl Bar { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const2", since = "1.2.0")] pub const fn stable_impl() -> u32 { 42 } - - // Show const-stability even for unstable functions. - //@ matches 'foo/struct.Bar.html' '//span[@class="since"]' '^const: 1.3.0$' - #[unstable(feature = "foo2", issue = "none")] - #[rustc_const_stable(feature = "const3", since = "1.3.0")] - pub const fn const_stable_unstable() -> u32 { 42 } } diff --git a/tests/ui/borrowck/issue-64453.rs b/tests/ui/borrowck/issue-64453.rs index 33d55be5812..5f1f35d6ca9 100644 --- a/tests/ui/borrowck/issue-64453.rs +++ b/tests/ui/borrowck/issue-64453.rs @@ -3,7 +3,6 @@ struct Value; static settings_dir: String = format!(""); //~^ ERROR cannot call non-const fn -//~| ERROR is not yet stable as a const fn from_string(_: String) -> Value { Value diff --git a/tests/ui/borrowck/issue-64453.stderr b/tests/ui/borrowck/issue-64453.stderr index e671817633b..98b05ead649 100644 --- a/tests/ui/borrowck/issue-64453.stderr +++ b/tests/ui/borrowck/issue-64453.stderr @@ -1,12 +1,3 @@ -error: `Arguments::<'a>::new_const` is not yet stable as a const fn - --> $DIR/issue-64453.rs:4:31 - | -LL | static settings_dir: String = format!(""); - | ^^^^^^^^^^^ - | - = help: add `#![feature(const_fmt_arguments_new)]` to the crate attributes to enable - = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0015]: cannot call non-const fn `format` in statics --> $DIR/issue-64453.rs:4:31 | @@ -18,7 +9,7 @@ LL | static settings_dir: String = format!(""); = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0507]: cannot move out of static item `settings_dir` - --> $DIR/issue-64453.rs:14:37 + --> $DIR/issue-64453.rs:13:37 | LL | let settings_data = from_string(settings_dir); | ^^^^^^^^^^^^ move occurs because `settings_dir` has type `String`, which does not implement the `Copy` trait @@ -28,7 +19,7 @@ help: consider cloning the value if the performance cost is acceptable LL | let settings_data = from_string(settings_dir.clone()); | ++++++++ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0015, E0507. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/auxiliary/unstable_but_const_stable.rs b/tests/ui/consts/auxiliary/unstable_but_const_stable.rs deleted file mode 100644 index 88044b0272c..00000000000 --- a/tests/ui/consts/auxiliary/unstable_but_const_stable.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![feature(staged_api, rustc_attrs, intrinsics)] -#![stable(since="1.0.0", feature = "stable")] - -extern "rust-intrinsic" { - #[unstable(feature = "unstable", issue = "42")] - #[rustc_const_stable(feature = "stable", since = "1.0.0")] - #[rustc_nounwind] - pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize); -} - -#[unstable(feature = "unstable", issue = "42")] -#[rustc_const_stable(feature = "stable", since = "1.0.0")] -pub const fn some_unstable_fn() {} diff --git a/tests/ui/consts/auxiliary/unstable_intrinsic.rs b/tests/ui/consts/auxiliary/unstable_intrinsic.rs new file mode 100644 index 00000000000..edef499dbb1 --- /dev/null +++ b/tests/ui/consts/auxiliary/unstable_intrinsic.rs @@ -0,0 +1,26 @@ +#![feature(staged_api, rustc_attrs, intrinsics)] +#![stable(since="1.0.0", feature = "stable")] + +#[stable(since="1.0.0", feature = "stable")] +pub mod old_way { + extern "rust-intrinsic" { + #[unstable(feature = "unstable", issue = "42")] + pub fn size_of_val<T>(x: *const T) -> usize; + + #[unstable(feature = "unstable", issue = "42")] + #[rustc_const_unstable(feature = "unstable", issue = "42")] + pub fn min_align_of_val<T>(x: *const T) -> usize; + } +} + +#[stable(since="1.0.0", feature = "stable")] +pub mod new_way { + #[unstable(feature = "unstable", issue = "42")] + #[rustc_intrinsic] + pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 } + + #[unstable(feature = "unstable", issue = "42")] + #[rustc_const_unstable(feature = "unstable", issue = "42")] + #[rustc_intrinsic] + pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize { 42 } +} diff --git a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs index 4b3cf70739c..6c93c0e63b6 100644 --- a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs +++ b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs @@ -3,7 +3,7 @@ we're apparently really bad at it", issue = "none")] -#![feature(staged_api)] +#![feature(staged_api, foo)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature="foo", issue = "none")] @@ -11,7 +11,7 @@ const fn foo() -> u32 { 42 } fn meh() -> u32 { 42 } -const fn bar() -> u32 { foo() } //~ ERROR `foo` is not yet stable as a const fn +const fn bar() -> u32 { foo() } //~ ERROR cannot use `#[feature(foo)]` fn a() { let _: &'static u32 = &foo(); //~ ERROR temporary value dropped while borrowed diff --git a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr index 2e697b219c5..1de1c78faf6 100644 --- a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr +++ b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr @@ -1,10 +1,20 @@ -error: `foo` is not yet stable as a const fn +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]` --> $DIR/dont_promote_unstable_const_fn.rs:14:25 | LL | const fn bar() -> u32 { foo() } | ^^^^^ | - = help: add `#![feature(foo)]` to the crate attributes to enable + = 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 bar() -> u32 { foo() } + | +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(foo)] +LL | const fn bar() -> u32 { foo() } + | error[E0716]: temporary value dropped while borrowed --> $DIR/dont_promote_unstable_const_fn.rs:17:28 diff --git a/tests/ui/consts/const-eval/simd/insert_extract.rs b/tests/ui/consts/const-eval/simd/insert_extract.rs index f4f25327aaf..57d4b4888ca 100644 --- a/tests/ui/consts/const-eval/simd/insert_extract.rs +++ b/tests/ui/consts/const-eval/simd/insert_extract.rs @@ -11,8 +11,11 @@ #[repr(simd)] struct f32x4([f32; 4]); extern "rust-intrinsic" { + #[stable(feature = "foo", since = "1.3.37")] #[rustc_const_stable(feature = "foo", since = "1.3.37")] fn simd_insert<T, U>(x: T, idx: u32, val: U) -> T; + + #[stable(feature = "foo", since = "1.3.37")] #[rustc_const_stable(feature = "foo", since = "1.3.37")] fn simd_extract<T, U>(x: T, idx: u32) -> U; } diff --git a/tests/ui/consts/const-unstable-intrinsic.rs b/tests/ui/consts/const-unstable-intrinsic.rs new file mode 100644 index 00000000000..050abc6dd46 --- /dev/null +++ b/tests/ui/consts/const-unstable-intrinsic.rs @@ -0,0 +1,76 @@ +//! Ensure that unstable intrinsics can actually not be called, +//! neither within a crate nor cross-crate. +//@ aux-build:unstable_intrinsic.rs +#![feature(staged_api, rustc_attrs, intrinsics)] +#![stable(since="1.0.0", feature = "stable")] +#![feature(local)] + +extern crate unstable_intrinsic; + +fn main() { + const_main(); +} + +const fn const_main() { + let x = 42; + unsafe { + unstable_intrinsic::old_way::size_of_val(&x); + //~^ERROR: unstable library feature 'unstable' + //~|ERROR: cannot call non-const intrinsic + unstable_intrinsic::old_way::min_align_of_val(&x); + //~^ERROR: unstable library feature 'unstable' + //~|ERROR: not yet stable as a const intrinsic + unstable_intrinsic::new_way::size_of_val(&x); + //~^ERROR: unstable library feature 'unstable' + //~|ERROR: cannot be (indirectly) exposed to stable + unstable_intrinsic::new_way::min_align_of_val(&x); + //~^ERROR: unstable library feature 'unstable' + //~|ERROR: not yet stable as a const intrinsic + + old_way::size_of_val(&x); + //~^ERROR: cannot call non-const intrinsic + old_way::min_align_of_val(&x); + //~^ERROR: cannot use `#[feature(local)]` + new_way::size_of_val(&x); + //~^ERROR: cannot be (indirectly) exposed to stable + new_way::min_align_of_val(&x); + //~^ERROR: cannot use `#[feature(local)]` + } +} + +#[stable(since="1.0.0", feature = "stable")] +pub mod old_way { + extern "rust-intrinsic" { + #[unstable(feature = "local", issue = "42")] + pub fn size_of_val<T>(x: *const T) -> usize; + + #[unstable(feature = "local", issue = "42")] + #[rustc_const_unstable(feature = "local", issue = "42")] + pub fn min_align_of_val<T>(x: *const T) -> usize; + } +} + +#[stable(since="1.0.0", feature = "stable")] +pub mod new_way { + #[unstable(feature = "local", issue = "42")] + #[rustc_intrinsic] + pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 } + + #[unstable(feature = "local", issue = "42")] + #[rustc_const_unstable(feature = "local", issue = "42")] + #[rustc_intrinsic] + pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize { 42 } +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] +#[inline] +pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) { + // Const stability attributes are not inherited from parent items. + extern "rust-intrinsic" { + fn copy<T>(src: *const T, dst: *mut T, count: usize); + } + + unsafe { copy(src, dst, count) } + //~^ ERROR cannot call non-const intrinsic +} diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr new file mode 100644 index 00000000000..33a434c503d --- /dev/null +++ b/tests/ui/consts/const-unstable-intrinsic.stderr @@ -0,0 +1,127 @@ +error[E0658]: use of unstable library feature 'unstable' + --> $DIR/const-unstable-intrinsic.rs:17:9 + | +LL | unstable_intrinsic::old_way::size_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information + = 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[E0658]: use of unstable library feature 'unstable' + --> $DIR/const-unstable-intrinsic.rs:20:9 + | +LL | unstable_intrinsic::old_way::min_align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information + = 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[E0658]: use of unstable library feature 'unstable' + --> $DIR/const-unstable-intrinsic.rs:23:9 + | +LL | unstable_intrinsic::new_way::size_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information + = 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[E0658]: use of unstable library feature 'unstable' + --> $DIR/const-unstable-intrinsic.rs:26:9 + | +LL | unstable_intrinsic::new_way::min_align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information + = 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: cannot call non-const intrinsic `size_of_val` in constant functions + --> $DIR/const-unstable-intrinsic.rs:17:9 + | +LL | unstable_intrinsic::old_way::size_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `min_align_of_val` is not yet stable as a const intrinsic + --> $DIR/const-unstable-intrinsic.rs:20:9 + | +LL | unstable_intrinsic::old_way::min_align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unstable)]` to the crate attributes to enable + +error: intrinsic `unstable_intrinsic::new_way::size_of_val` cannot be (indirectly) exposed to stable + --> $DIR/const-unstable-intrinsic.rs:23:9 + | +LL | unstable_intrinsic::new_way::size_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval) + +error: `min_align_of_val` is not yet stable as a const intrinsic + --> $DIR/const-unstable-intrinsic.rs:26:9 + | +LL | unstable_intrinsic::new_way::min_align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unstable)]` to the crate attributes to enable + +error: cannot call non-const intrinsic `size_of_val` in constant functions + --> $DIR/const-unstable-intrinsic.rs:30:9 + | +LL | old_way::size_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]` + --> $DIR/const-unstable-intrinsic.rs:32:9 + | +LL | old_way::min_align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +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: intrinsic `new_way::size_of_val` cannot be (indirectly) exposed to stable + --> $DIR/const-unstable-intrinsic.rs:34:9 + | +LL | new_way::size_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval) + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]` + --> $DIR/const-unstable-intrinsic.rs:36:9 + | +LL | new_way::min_align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +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: cannot call non-const intrinsic `copy` in constant functions + --> $DIR/const-unstable-intrinsic.rs:74:14 + | +LL | unsafe { copy(src, dst, count) } + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 13 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/copy-intrinsic.rs b/tests/ui/consts/copy-intrinsic.rs index 805c03da546..62917c0b98b 100644 --- a/tests/ui/consts/copy-intrinsic.rs +++ b/tests/ui/consts/copy-intrinsic.rs @@ -5,9 +5,11 @@ use std::mem; extern "rust-intrinsic" { + #[stable(feature = "dummy", since = "1.0.0")] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize); + #[stable(feature = "dummy", since = "1.0.0")] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] fn copy<T>(src: *const T, dst: *mut T, count: usize); } diff --git a/tests/ui/consts/copy-intrinsic.stderr b/tests/ui/consts/copy-intrinsic.stderr index da8139129c9..29a88f6270b 100644 --- a/tests/ui/consts/copy-intrinsic.stderr +++ b/tests/ui/consts/copy-intrinsic.stderr @@ -1,23 +1,23 @@ error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:28:5 + --> $DIR/copy-intrinsic.rs:30:5 | LL | copy_nonoverlapping(0x100 as *const i32, dangle, 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x100[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:37:5 + --> $DIR/copy-intrinsic.rs:39:5 | LL | copy_nonoverlapping(dangle, 0x100 as *mut i32, 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:44:5 + --> $DIR/copy-intrinsic.rs:46:5 | LL | copy(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy` error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:50:5 + --> $DIR/copy-intrinsic.rs:52:5 | LL | copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy_nonoverlapping` diff --git a/tests/ui/consts/intrinsic_without_const_stab.rs b/tests/ui/consts/intrinsic_without_const_stab.rs deleted file mode 100644 index 40ec65d51be..00000000000 --- a/tests/ui/consts/intrinsic_without_const_stab.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![feature(intrinsics, staged_api)] -#![stable(feature = "core", since = "1.6.0")] - -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] -#[inline] -pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) { - // Const stability attributes are not inherited from parent items. - extern "rust-intrinsic" { - fn copy<T>(src: *const T, dst: *mut T, count: usize); - } - - unsafe { copy(src, dst, count) } - //~^ ERROR cannot call non-const fn -} - -fn main() {} diff --git a/tests/ui/consts/intrinsic_without_const_stab.stderr b/tests/ui/consts/intrinsic_without_const_stab.stderr deleted file mode 100644 index e3143080c5f..00000000000 --- a/tests/ui/consts/intrinsic_without_const_stab.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0015]: cannot call non-const fn `copy::copy::<T>` in constant functions - --> $DIR/intrinsic_without_const_stab.rs:13:14 - | -LL | unsafe { copy(src, dst, count) } - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/intrinsic_without_const_stab_fail.rs b/tests/ui/consts/intrinsic_without_const_stab_fail.rs deleted file mode 100644 index 2b0745b3c11..00000000000 --- a/tests/ui/consts/intrinsic_without_const_stab_fail.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![feature(intrinsics, staged_api)] -#![stable(feature = "core", since = "1.6.0")] - -extern "rust-intrinsic" { - fn copy<T>(src: *const T, dst: *mut T, count: usize); -} - -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] -#[inline] -pub const unsafe fn stuff<T>(src: *const T, dst: *mut T, count: usize) { - unsafe { copy(src, dst, count) } //~ ERROR cannot call non-const fn -} - -fn main() {} diff --git a/tests/ui/consts/intrinsic_without_const_stab_fail.stderr b/tests/ui/consts/intrinsic_without_const_stab_fail.stderr deleted file mode 100644 index 8ade68eb2a9..00000000000 --- a/tests/ui/consts/intrinsic_without_const_stab_fail.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0015]: cannot call non-const fn `copy::<T>` in constant functions - --> $DIR/intrinsic_without_const_stab_fail.rs:12:14 - | -LL | unsafe { copy(src, dst, count) } - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs index 461499e942f..d6f07994e82 100644 --- a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs +++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs @@ -5,7 +5,7 @@ issue = "none")] #![feature(foo, foo2)] -#![feature(const_async_blocks, staged_api)] +#![feature(const_async_blocks, staged_api, rustc_attrs)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature="foo", issue = "none")] @@ -14,33 +14,55 @@ const fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn +const fn bar() -> u32 { foo() } //~ ERROR cannot use `#[feature(foo)]` #[unstable(feature = "foo2", issue = "none")] +#[rustc_const_unstable(feature = "foo2", issue = "none")] const fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn +const fn bar2() -> u32 { foo2() } //~ ERROR cannot use `#[feature(foo2)]` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // conformity is required const fn bar3() -> u32 { let x = async { 13 }; - //~^ ERROR const-stable function cannot use `#[feature(const_async_blocks)]` + //~^ ERROR cannot use `#[feature(const_async_blocks)]` foo() - //~^ ERROR is not yet stable as a const fn + //~^ ERROR cannot use `#[feature(foo)]` } // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] +#[rustc_const_unstable(feature = "foo2", issue = "none")] const fn foo2_gated() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn +const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]` + +// Functions without any attribute are checked like stable functions, +// even if they are in a stable module. +mod stable { + #![stable(feature = "rust1", since = "1.0.0")] + + pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]` +} +// And same for const-unstable functions that are marked as "stable_indirect". +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature="foo", issue = "none")] +#[rustc_const_stable_indirect] +const fn stable_indirect() -> u32 { foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]` + +// These functiuons *can* be called from fully stable functions. +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "rust1", since = "1.0.0")] +const fn bar2_gated_exposed() -> u32 { + stable::bar2_gated_stable_indirect() + stable_indirect() +} fn main() {} diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr index fedc5a4809d..899cec07ac7 100644 --- a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr +++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr @@ -1,51 +1,127 @@ -error: `foo` is not yet stable as a const fn +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]` --> $DIR/min_const_fn_libstd_stability.rs:17:25 | LL | const fn bar() -> u32 { foo() } | ^^^^^ | - = help: const-stable functions can only call other const-stable functions + = 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 bar() -> u32 { foo() } + | +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(foo)] +LL | const fn bar() -> u32 { foo() } + | -error: `foo2` is not yet stable as a const fn - --> $DIR/min_const_fn_libstd_stability.rs:25:26 +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]` + --> $DIR/min_const_fn_libstd_stability.rs:26:26 | LL | const fn bar2() -> u32 { foo2() } | ^^^^^^ | - = help: const-stable functions can only call other const-stable functions + = 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 bar2() -> u32 { foo2() } + | +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(foo2)] +LL | const fn bar2() -> u32 { foo2() } + | -error: const-stable function cannot use `#[feature(const_async_blocks)]` - --> $DIR/min_const_fn_libstd_stability.rs:31:13 +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_async_blocks)]` + --> $DIR/min_const_fn_libstd_stability.rs:32:13 | LL | let x = async { 13 }; | ^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be stable, make this function unstably const +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 bar3() -> u32 { | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (but requires team approval) +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 | const fn bar3() -> u32 { | -error: `foo` is not yet stable as a const fn - --> $DIR/min_const_fn_libstd_stability.rs:33:5 +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]` + --> $DIR/min_const_fn_libstd_stability.rs:34:5 | LL | foo() | ^^^^^ | - = help: const-stable functions can only call other const-stable functions + = 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 bar3() -> u32 { + | +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(foo)] +LL | const fn bar3() -> u32 { + | -error: `foo2_gated` is not yet stable as a const fn - --> $DIR/min_const_fn_libstd_stability.rs:44:32 +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]` + --> $DIR/min_const_fn_libstd_stability.rs:46:32 | LL | const fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | - = help: const-stable functions can only call other const-stable functions + = 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 bar2_gated() -> u32 { foo2_gated() } + | +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(foo2)] +LL | const fn bar2_gated() -> u32 { foo2_gated() } + | + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]` + --> $DIR/min_const_fn_libstd_stability.rs:53:63 + | +LL | pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() } + | ^^^^^^^^^^^^^^^^^^^ + | + = 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(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() } + | +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(foo2)] +LL | pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() } + | + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]` + --> $DIR/min_const_fn_libstd_stability.rs:59:37 + | +LL | const fn stable_indirect() -> u32 { foo2_gated() } + | ^^^^^^^^^^^^ + | + = 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_indirect() -> u32 { foo2_gated() } + | +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(foo2)] +LL | const fn stable_indirect() -> u32 { foo2_gated() } + | -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs index 274b4444799..3e82b9ff924 100644 --- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs +++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs @@ -13,24 +13,26 @@ const unsafe fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR not yet stable as a const fn +const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR cannot use `#[feature(foo)]` #[unstable(feature = "foo2", issue = "none")] +#[rustc_const_unstable(feature = "foo2", issue = "none")] const unsafe fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR not yet stable as a const fn +const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR cannot use `#[feature(foo2)]` // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] +#[rustc_const_unstable(feature = "foo2", issue = "none")] const unsafe fn foo2_gated() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } -//~^ ERROR not yet stable as a const fn +//~^ ERROR cannot use `#[feature(foo2)]` fn main() {} diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr index 353b117efbc..442a079020f 100644 --- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr +++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr @@ -1,26 +1,56 @@ -error: `foo` is not yet stable as a const fn +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]` --> $DIR/min_const_unsafe_fn_libstd_stability.rs:16:41 | LL | const unsafe fn bar() -> u32 { unsafe { foo() } } | ^^^^^ | - = help: const-stable functions can only call other const-stable functions + = 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 unsafe fn bar() -> u32 { unsafe { foo() } } + | +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(foo)] +LL | const unsafe fn bar() -> u32 { unsafe { foo() } } + | -error: `foo2` is not yet stable as a const fn - --> $DIR/min_const_unsafe_fn_libstd_stability.rs:24:42 +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]` + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:25:42 | LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } | ^^^^^^ | - = help: const-stable functions can only call other const-stable functions + = 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 unsafe fn bar2() -> u32 { unsafe { foo2() } } + | +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(foo2)] +LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } + | -error: `foo2_gated` is not yet stable as a const fn - --> $DIR/min_const_unsafe_fn_libstd_stability.rs:33:48 +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]` + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:35:48 | LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } | ^^^^^^^^^^^^ | - = help: const-stable functions can only call other const-stable functions + = 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 unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } + | +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(foo2)] +LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } + | error: aborting due to 3 previous errors diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs index 94b62071362..cc7eaa51a6f 100644 --- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs +++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs @@ -13,23 +13,25 @@ const fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn +const unsafe fn bar() -> u32 { foo() } //~ ERROR cannot use `#[feature(foo)]` #[unstable(feature = "foo2", issue = "none")] +#[rustc_const_unstable(feature="foo2", issue = "none")] const fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn +const unsafe fn bar2() -> u32 { foo2() } //~ ERROR cannot use `#[feature(foo2)]` // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] +#[rustc_const_unstable(feature="foo2", issue = "none")] const fn foo2_gated() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn +const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]` fn main() {} diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr index e90ba9b912f..ff37cba7b9a 100644 --- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr +++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr @@ -1,26 +1,56 @@ -error: `foo` is not yet stable as a const fn +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]` --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:16:32 | LL | const unsafe fn bar() -> u32 { foo() } | ^^^^^ | - = help: const-stable functions can only call other const-stable functions + = 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 unsafe fn bar() -> u32 { foo() } + | +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(foo)] +LL | const unsafe fn bar() -> u32 { foo() } + | -error: `foo2` is not yet stable as a const fn - --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:24:33 +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]` + --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:25:33 | LL | const unsafe fn bar2() -> u32 { foo2() } | ^^^^^^ | - = help: const-stable functions can only call other const-stable functions + = 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 unsafe fn bar2() -> u32 { foo2() } + | +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(foo2)] +LL | const unsafe fn bar2() -> u32 { foo2() } + | -error: `foo2_gated` is not yet stable as a const fn - --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:39 +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]` + --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:35:39 | LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | - = help: const-stable functions can only call other const-stable functions + = 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 unsafe fn bar2_gated() -> u32 { foo2_gated() } + | +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(foo2)] +LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } + | error: aborting due to 3 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 4fb259b335c..1c66f6e2aa5 100644 --- a/tests/ui/consts/rustc-const-stability-require-const.rs +++ b/tests/ui/consts/rustc-const-stability-require-const.rs @@ -1,16 +1,16 @@ #![crate_type = "lib"] -#![feature(staged_api)] +#![feature(staged_api, rustc_attrs)] #![stable(feature = "foo", since = "1.0.0")] #[stable(feature = "foo", since = "1.0.0")] #[rustc_const_unstable(feature = "const_foo", issue = "none")] pub fn foo() {} -//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +//~^ ERROR require the function or method to be `const` #[stable(feature = "bar", since = "1.0.0")] #[rustc_const_stable(feature = "const_bar", since = "1.0.0")] pub fn bar() {} -//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +//~^ ERROR require the function or method to be `const` #[stable(feature = "potato", since = "1.0.0")] pub struct Potato; @@ -19,23 +19,23 @@ impl Potato { #[stable(feature = "salad", since = "1.0.0")] #[rustc_const_unstable(feature = "const_salad", issue = "none")] pub fn salad(&self) -> &'static str { "mmmmmm" } - //~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` + //~^ ERROR require the function or method to be `const` #[stable(feature = "roasted", since = "1.0.0")] #[rustc_const_unstable(feature = "const_roasted", issue = "none")] pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" } - //~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` + //~^ ERROR require the function or method to be `const` } #[stable(feature = "bar", since = "1.0.0")] #[rustc_const_stable(feature = "const_bar", since = "1.0.0")] pub extern "C" fn bar_c() {} -//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +//~^ ERROR require the function or method to be `const` #[stable(feature = "foo", since = "1.0.0")] #[rustc_const_unstable(feature = "const_foo", issue = "none")] pub extern "C" fn foo_c() {} -//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +//~^ ERROR require the function or method to be `const` #[stable(feature = "foobar", since = "1.0.0")] @@ -45,3 +45,21 @@ pub const fn foobar() {} #[stable(feature = "barfoo", since = "1.0.0")] #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")] pub const fn barfoo() {} + +// `rustc_const_stable` also requires the function to be stable. +// FIXME: these are disabled until <https://github.com/rust-lang/stdarch/pull/1654> propagates. + +#[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")] +const fn barfoo_unmarked() {} +// FIXME disabled ERROR can only be applied to functions that are declared `#[stable]` + +#[unstable(feature = "unstable", issue = "none")] +#[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")] +pub const fn barfoo_unstable() {} +// FIXME disabled 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 1027b9311b7..09b96ce6f83 100644 --- a/tests/ui/consts/rustc-const-stability-require-const.stderr +++ b/tests/ui/consts/rustc-const-stability-require-const.stderr @@ -1,8 +1,6 @@ -error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +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:7:1 | -LL | #[rustc_const_unstable(feature = "const_foo", issue = "none")] - | -------------------------------------------------------------- attribute specified here LL | pub fn foo() {} | ^^^^^^^^^^^^ | @@ -12,11 +10,9 @@ help: make the function or method const LL | pub fn foo() {} | ^^^^^^^^^^^^ -error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +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:12:1 | -LL | #[rustc_const_stable(feature = "const_bar", since = "1.0.0")] - | ------------------------------------------------------------- attribute specified here LL | pub fn bar() {} | ^^^^^^^^^^^^ | @@ -26,11 +22,9 @@ help: make the function or method const LL | pub fn bar() {} | ^^^^^^^^^^^^ -error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +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:21:5 | -LL | #[rustc_const_unstable(feature = "const_salad", issue = "none")] - | ---------------------------------------------------------------- attribute specified here LL | pub fn salad(&self) -> &'static str { "mmmmmm" } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -40,11 +34,9 @@ help: make the function or method const LL | pub fn salad(&self) -> &'static str { "mmmmmm" } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +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:26:5 | -LL | #[rustc_const_unstable(feature = "const_roasted", issue = "none")] - | ------------------------------------------------------------------ attribute specified here LL | pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -54,11 +46,9 @@ help: make the function or method const LL | pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +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:32:1 | -LL | #[rustc_const_stable(feature = "const_bar", since = "1.0.0")] - | ------------------------------------------------------------- attribute specified here LL | pub extern "C" fn bar_c() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -68,11 +58,9 @@ help: make the function or method const LL | pub extern "C" fn bar_c() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +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:37:1 | -LL | #[rustc_const_unstable(feature = "const_foo", issue = "none")] - | -------------------------------------------------------------- attribute specified here LL | pub extern "C" fn foo_c() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -82,5 +70,17 @@ help: make the function or method const LL | pub extern "C" fn foo_c() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +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:64:1 + | +LL | pub fn not_a_const_fn() {} + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function or method const + --> $DIR/rustc-const-stability-require-const.rs:64:1 + | +LL | pub fn not_a_const_fn() {} + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 7 previous errors diff --git a/tests/ui/consts/unstable-const-stable.rs b/tests/ui/consts/unstable-const-stable.rs deleted file mode 100644 index f69e8d0efe5..00000000000 --- a/tests/ui/consts/unstable-const-stable.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ aux-build:unstable_but_const_stable.rs - -extern crate unstable_but_const_stable; -use unstable_but_const_stable::*; - -fn main() { - some_unstable_fn(); //~ERROR use of unstable library feature - unsafe { write_bytes(4 as *mut u8, 0, 0) }; //~ERROR use of unstable library feature -} - -const fn const_main() { - some_unstable_fn(); //~ERROR use of unstable library feature - unsafe { write_bytes(4 as *mut u8, 0, 0) }; //~ERROR use of unstable library feature -} diff --git a/tests/ui/consts/unstable-const-stable.stderr b/tests/ui/consts/unstable-const-stable.stderr deleted file mode 100644 index c4ffbbb60db..00000000000 --- a/tests/ui/consts/unstable-const-stable.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0658]: use of unstable library feature 'unstable' - --> $DIR/unstable-const-stable.rs:7:5 - | -LL | some_unstable_fn(); - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information - = 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[E0658]: use of unstable library feature 'unstable' - --> $DIR/unstable-const-stable.rs:8:14 - | -LL | unsafe { write_bytes(4 as *mut u8, 0, 0) }; - | ^^^^^^^^^^^ - | - = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information - = 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[E0658]: use of unstable library feature 'unstable' - --> $DIR/unstable-const-stable.rs:12:5 - | -LL | some_unstable_fn(); - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information - = 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[E0658]: use of unstable library feature 'unstable' - --> $DIR/unstable-const-stable.rs:13:14 - | -LL | unsafe { write_bytes(4 as *mut u8, 0, 0) }; - | ^^^^^^^^^^^ - | - = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information - = 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: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0658`. 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 319056a9c88..d599523c727 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,31 +1,31 @@ error: can't mark as unstable using an already stable feature - --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1 + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 | -LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable 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:6:1 + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 | -LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +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:7:1 + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1 | +LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable 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 + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1 | -LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/intrinsics/const-eval-select-stability.rs b/tests/ui/intrinsics/const-eval-select-stability.rs index 575bc0cadda..25cbadaa22d 100644 --- a/tests/ui/intrinsics/const-eval-select-stability.rs +++ b/tests/ui/intrinsics/const-eval-select-stability.rs @@ -15,7 +15,7 @@ const fn nothing(){} #[rustc_const_stable(since = "1.0", feature = "const_hey")] pub const fn hey() { const_eval_select((), nothing, log); - //~^ ERROR `const_eval_select` is not yet stable as a const fn + //~^ ERROR cannot use `#[feature(const_eval_select)]` } fn main() {} diff --git a/tests/ui/intrinsics/const-eval-select-stability.stderr b/tests/ui/intrinsics/const-eval-select-stability.stderr index 335b9877aa0..5f443b1d4ff 100644 --- a/tests/ui/intrinsics/const-eval-select-stability.stderr +++ b/tests/ui/intrinsics/const-eval-select-stability.stderr @@ -1,10 +1,19 @@ -error: `const_eval_select` is not yet stable as a const fn +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_eval_select)]` --> $DIR/const-eval-select-stability.rs:17:5 | LL | const_eval_select((), nothing, log); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: const-stable functions can only call other const-stable functions +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 hey() { + | +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_eval_select)] +LL | pub const fn hey() { + | error: aborting due to 1 previous error diff --git a/tests/ui/layout/post-mono-layout-cycle-2.rs b/tests/ui/layout/post-mono-layout-cycle-2.rs index e9a5292fbbd..356f1e777c7 100644 --- a/tests/ui/layout/post-mono-layout-cycle-2.rs +++ b/tests/ui/layout/post-mono-layout-cycle-2.rs @@ -45,6 +45,7 @@ where T: Blah, { async fn ice(&mut self) { + //~^ ERROR a cycle occurred during layout computation let arr: [(); 0] = []; self.t.iter(arr.into_iter()).await; } diff --git a/tests/ui/layout/post-mono-layout-cycle-2.stderr b/tests/ui/layout/post-mono-layout-cycle-2.stderr index ea69b39706f..ad01c2694fa 100644 --- a/tests/ui/layout/post-mono-layout-cycle-2.stderr +++ b/tests/ui/layout/post-mono-layout-cycle-2.stderr @@ -12,12 +12,12 @@ LL | Blah::iter(self, iterator).await | = note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future -note: the above error was encountered while instantiating `fn main::{closure#0}` - --> $DIR/post-mono-layout-cycle-2.rs:16:15 +error: a cycle occurred during layout computation + --> $DIR/post-mono-layout-cycle-2.rs:47:5 | -LL | match fut.as_mut().poll(ctx) { - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | async fn ice(&mut self) { + | ^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0733`. diff --git a/tests/ui/layout/post-mono-layout-cycle.rs b/tests/ui/layout/post-mono-layout-cycle.rs index 6753c01267e..8d136190c00 100644 --- a/tests/ui/layout/post-mono-layout-cycle.rs +++ b/tests/ui/layout/post-mono-layout-cycle.rs @@ -14,6 +14,7 @@ struct Wrapper<T: Trait> { } fn abi<T: Trait>(_: Option<Wrapper<T>>) {} +//~^ ERROR a cycle occurred during layout computation fn indirect<T: Trait>() { abi::<T>(None); diff --git a/tests/ui/layout/post-mono-layout-cycle.stderr b/tests/ui/layout/post-mono-layout-cycle.stderr index e2f6ac595d0..47f7f30b1cb 100644 --- a/tests/ui/layout/post-mono-layout-cycle.stderr +++ b/tests/ui/layout/post-mono-layout-cycle.stderr @@ -5,12 +5,12 @@ error[E0391]: cycle detected when computing layout of `Wrapper<()>` = note: cycle used when computing layout of `core::option::Option<Wrapper<()>>` = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -note: the above error was encountered while instantiating `fn indirect::<()>` - --> $DIR/post-mono-layout-cycle.rs:23:5 +error: a cycle occurred during layout computation + --> $DIR/post-mono-layout-cycle.rs:16:1 | -LL | indirect::<()>(); - | ^^^^^^^^^^^^^^^^ +LL | fn abi<T: Trait>(_: Option<Wrapper<T>>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/simd-abi-checks.rs b/tests/ui/simd-abi-checks.rs deleted file mode 100644 index 094c89930b7..00000000000 --- a/tests/ui/simd-abi-checks.rs +++ /dev/null @@ -1,81 +0,0 @@ -//@ only-x86_64 -//@ build-pass -//@ ignore-pass (test emits codegen-time warnings) - -#![feature(avx512_target_feature)] -#![feature(portable_simd)] -#![allow(improper_ctypes_definitions)] - -use std::arch::x86_64::*; - -#[repr(transparent)] -struct Wrapper(__m256); - -unsafe extern "C" fn w(_: Wrapper) { - //~^ ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled - //~| WARNING this was previously accepted by the compiler - todo!() -} - -unsafe extern "C" fn f(_: __m256) { - //~^ ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled - //~| WARNING this was previously accepted by the compiler - todo!() -} - -unsafe extern "C" fn g() -> __m256 { - //~^ ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled - //~| WARNING this was previously accepted by the compiler - todo!() -} - -#[target_feature(enable = "avx")] -unsafe extern "C" fn favx() -> __m256 { - todo!() -} - -// avx2 implies avx, so no error here. -#[target_feature(enable = "avx2")] -unsafe extern "C" fn gavx(_: __m256) { - todo!() -} - -// No error because of "Rust" ABI. -fn as_f64x8(d: __m512d) -> std::simd::f64x8 { - unsafe { std::mem::transmute(d) } -} - -unsafe fn test() { - let arg = std::mem::transmute([0.0f64; 8]); - as_f64x8(arg); -} - -fn main() { - unsafe { - f(g()); - //~^ WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller - //~| WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller - //~| WARNING this was previously accepted by the compiler - //~| WARNING this was previously accepted by the compiler - } - - unsafe { - gavx(favx()); - //~^ WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller - //~| WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller - //~| WARNING this was previously accepted by the compiler - //~| WARNING this was previously accepted by the compiler - } - - unsafe { - test(); - } - - unsafe { - w(Wrapper(g())); - //~^ WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller - //~| WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller - //~| WARNING this was previously accepted by the compiler - //~| WARNING this was previously accepted by the compiler - } -} diff --git a/tests/ui/simd-abi-checks.stderr b/tests/ui/simd-abi-checks.stderr deleted file mode 100644 index aa7e9400169..00000000000 --- a/tests/ui/simd-abi-checks.stderr +++ /dev/null @@ -1,93 +0,0 @@ -warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks.rs:55:11 - | -LL | f(g()); - | ^^^ function called here - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> - = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) - = note: `#[warn(abi_unsupported_vector_types)]` on by default - -warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks.rs:55:9 - | -LL | f(g()); - | ^^^^^^ function called here - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> - = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) - -warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks.rs:63:14 - | -LL | gavx(favx()); - | ^^^^^^ function called here - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> - = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) - -warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks.rs:63:9 - | -LL | gavx(favx()); - | ^^^^^^^^^^^^ function called here - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> - = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) - -warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks.rs:75:19 - | -LL | w(Wrapper(g())); - | ^^^ function called here - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> - = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) - -warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks.rs:75:9 - | -LL | w(Wrapper(g())); - | ^^^^^^^^^^^^^^^ function called here - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> - = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) - -warning: ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled - --> $DIR/simd-abi-checks.rs:26:1 - | -LL | unsafe extern "C" fn g() -> __m256 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> - = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) - -warning: ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled - --> $DIR/simd-abi-checks.rs:20:1 - | -LL | unsafe extern "C" fn f(_: __m256) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> - = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) - -warning: ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled - --> $DIR/simd-abi-checks.rs:14:1 - | -LL | unsafe extern "C" fn w(_: Wrapper) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> - = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) - -warning: 9 warnings emitted - diff --git a/tests/ui/sse-abi-checks.rs b/tests/ui/sse-abi-checks.rs deleted file mode 100644 index d2afd38fcc8..00000000000 --- a/tests/ui/sse-abi-checks.rs +++ /dev/null @@ -1,24 +0,0 @@ -//! Ensure we trigger abi_unsupported_vector_types for target features that are usually enabled -//! on a target, but disabled in this file via a `-C` flag. -//@ compile-flags: --crate-type=rlib --target=i686-unknown-linux-gnu -C target-feature=-sse,-sse2 -//@ build-pass -//@ ignore-pass (test emits codegen-time warnings) -//@ needs-llvm-components: x86 -#![feature(no_core, lang_items, repr_simd)] -#![no_core] -#![allow(improper_ctypes_definitions)] - -#[lang = "sized"] -trait Sized {} - -#[lang = "copy"] -trait Copy {} - -#[repr(simd)] -pub struct SseVector([i64; 2]); - -#[no_mangle] -pub unsafe extern "C" fn f(_: SseVector) { - //~^ ABI error: this function definition uses a vector type that requires the `sse` target feature, which is not enabled - //~| WARNING this was previously accepted by the compiler -} diff --git a/tests/ui/sse-abi-checks.stderr b/tests/ui/sse-abi-checks.stderr deleted file mode 100644 index 77c4e1fc07a..00000000000 --- a/tests/ui/sse-abi-checks.stderr +++ /dev/null @@ -1,13 +0,0 @@ -warning: ABI error: this function definition uses a vector type that requires the `sse` target feature, which is not enabled - --> $DIR/sse-abi-checks.rs:21:1 - | -LL | pub unsafe extern "C" fn f(_: SseVector) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> - = help: consider enabling it globally (`-C target-feature=+sse`) or locally (`#[target_feature(enable="sse")]`) - = note: `#[warn(abi_unsupported_vector_types)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs index 4089ec72885..6d6d793c62b 100644 --- a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs +++ b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs @@ -14,4 +14,3 @@ pub const fn foobar() -> u32 { } const VAR: u32 = foobar(); -//~^ ERROR: `foobar` is not yet stable as a const fn diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr index 918d6ebf992..232de41c769 100644 --- a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr +++ b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr @@ -4,13 +4,5 @@ error: feature `const_bar` implying `const_foobar` does not exist LL | #[rustc_const_unstable(feature = "const_foobar", issue = "1", implied_by = "const_bar")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `foobar` is not yet stable as a const fn - --> $DIR/const-stability-attribute-implies-missing.rs:16:18 - | -LL | const VAR: u32 = foobar(); - | ^^^^^^^^ - | - = help: add `#![feature(const_foobar)]` to the crate attributes to enable - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/stability-attribute/missing-const-stability.rs b/tests/ui/stability-attribute/missing-const-stability.rs index 82da18cc9ac..f1139652550 100644 --- a/tests/ui/stability-attribute/missing-const-stability.rs +++ b/tests/ui/stability-attribute/missing-const-stability.rs @@ -1,6 +1,6 @@ //@ compile-flags: -Znext-solver #![feature(staged_api)] -#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete +#![feature(const_trait_impl, effects, rustc_attrs, intrinsics)] //~ WARN the feature `effects` is incomplete #![stable(feature = "stable", since = "1.0.0")] #[stable(feature = "stable", since = "1.0.0")] @@ -31,4 +31,15 @@ impl const Bar for Foo { fn fun() {} } +#[stable(feature = "stable", since = "1.0.0")] +#[rustc_intrinsic] +pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 } +//~^ ERROR function has missing const stability attribute + +extern "rust-intrinsic" { + #[stable(feature = "stable", since = "1.0.0")] + #[rustc_const_stable_indirect] + pub fn min_align_of_val<T>(x: *const T) -> usize; +} + fn main() {} diff --git a/tests/ui/stability-attribute/missing-const-stability.stderr b/tests/ui/stability-attribute/missing-const-stability.stderr index adf60c38611..e62a8b88261 100644 --- a/tests/ui/stability-attribute/missing-const-stability.stderr +++ b/tests/ui/stability-attribute/missing-const-stability.stderr @@ -1,7 +1,7 @@ warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/missing-const-stability.rs:3:30 | -LL | #![feature(const_trait_impl, effects)] +LL | #![feature(const_trait_impl, effects, rustc_attrs, intrinsics)] | ^^^^^^^ | = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information @@ -22,11 +22,17 @@ LL | | fn fun() {} LL | | } | |_^ +error: function has missing const stability attribute + --> $DIR/missing-const-stability.rs:36:1 + | +LL | pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: associated function has missing const stability attribute --> $DIR/missing-const-stability.rs:16:5 | LL | pub const fn foo() {} | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 4 previous errors; 1 warning emitted diff --git a/tests/ui/target-feature/feature-hierarchy.rs b/tests/ui/target-feature/feature-hierarchy.rs index 4cf9112810c..7f14d700ecb 100644 --- a/tests/ui/target-feature/feature-hierarchy.rs +++ b/tests/ui/target-feature/feature-hierarchy.rs @@ -19,6 +19,7 @@ trait Copy {} impl Copy for bool {} extern "rust-intrinsic" { + #[stable(feature = "test", since = "1.0.0")] #[rustc_const_stable(feature = "test", since = "1.0.0")] fn unreachable() -> !; } diff --git a/tests/ui/target-feature/no-llvm-leaks.rs b/tests/ui/target-feature/no-llvm-leaks.rs index 9f5dec4447f..f0c887bc1e0 100644 --- a/tests/ui/target-feature/no-llvm-leaks.rs +++ b/tests/ui/target-feature/no-llvm-leaks.rs @@ -17,6 +17,7 @@ trait Copy {} impl Copy for bool {} extern "rust-intrinsic" { + #[stable(feature = "test", since = "1.0.0")] #[rustc_const_stable(feature = "test", since = "1.0.0")] fn unreachable() -> !; } diff --git a/tests/ui/traits/const-traits/auxiliary/staged-api.rs b/tests/ui/traits/const-traits/auxiliary/staged-api.rs index 986165ef91e..bb591321b84 100644 --- a/tests/ui/traits/const-traits/auxiliary/staged-api.rs +++ b/tests/ui/traits/const-traits/auxiliary/staged-api.rs @@ -19,3 +19,12 @@ pub struct Unstable; impl const MyTrait for Unstable { fn func() {} } + +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Unstable2; + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "unstable2", issue = "none")] +impl const MyTrait for Unstable2 { + fn func() {} +} diff --git a/tests/ui/traits/const-traits/effects/minicore.rs b/tests/ui/traits/const-traits/effects/minicore.rs index a756f4d9f6c..1f0d22eeb38 100644 --- a/tests/ui/traits/const-traits/effects/minicore.rs +++ b/tests/ui/traits/const-traits/effects/minicore.rs @@ -515,7 +515,7 @@ trait StructuralPartialEq {} const fn drop<T: ~const Destruct>(_: T) {} -#[rustc_const_stable(feature = "const_eval_select", since = "1.0.0")] +#[rustc_const_stable_indirect] #[rustc_intrinsic_must_be_overridden] #[rustc_intrinsic] const fn const_eval_select<ARG: Tuple, F, G, RET>( diff --git a/tests/ui/traits/const-traits/issue-79450.rs b/tests/ui/traits/const-traits/issue-79450.rs index b8b9e07b3bd..cdefebc87d6 100644 --- a/tests/ui/traits/const-traits/issue-79450.rs +++ b/tests/ui/traits/const-traits/issue-79450.rs @@ -1,6 +1,5 @@ //@ compile-flags: -Znext-solver #![allow(incomplete_features)] -#![feature(const_fmt_arguments_new)] #![feature(const_trait_impl, effects)] #[const_trait] diff --git a/tests/ui/traits/const-traits/issue-79450.stderr b/tests/ui/traits/const-traits/issue-79450.stderr index 9e6348d37ed..49f380c1a2b 100644 --- a/tests/ui/traits/const-traits/issue-79450.stderr +++ b/tests/ui/traits/const-traits/issue-79450.stderr @@ -1,5 +1,5 @@ error[E0015]: cannot call non-const fn `_print` in constant functions - --> $DIR/issue-79450.rs:11:9 + --> $DIR/issue-79450.rs:10:9 | LL | println!("lul"); | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/traits/const-traits/staged-api.rs b/tests/ui/traits/const-traits/staged-api.rs index f87e723472a..59fe6d52d5d 100644 --- a/tests/ui/traits/const-traits/staged-api.rs +++ b/tests/ui/traits/const-traits/staged-api.rs @@ -2,6 +2,7 @@ //@ compile-flags: -Znext-solver #![cfg_attr(unstable, feature(unstable))] // The feature from the ./auxiliary/staged-api.rs file. +#![cfg_attr(unstable, feature(local_feature))] #![feature(const_trait_impl, effects)] #![allow(incomplete_features)] #![feature(staged_api)] @@ -16,8 +17,8 @@ use staged_api::*; pub struct Foo; #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(unstable, rustc_const_unstable(feature = "foo", issue = "none"))] -#[cfg_attr(stable, rustc_const_stable(feature = "foo", since = "1.0.0"))] +#[cfg_attr(unstable, rustc_const_unstable(feature = "local_feature", issue = "none"))] +#[cfg_attr(stable, rustc_const_stable(feature = "local_feature", since = "1.0.0"))] impl const MyTrait for Foo { //[stable]~^ ERROR trait implementations cannot be const stable yet fn func() {} @@ -32,32 +33,43 @@ fn non_const_context() { #[unstable(feature = "none", issue = "none")] const fn const_context() { Unstable::func(); - //[stable]~^ ERROR not yet stable as a const fn + //[unstable]~^ ERROR cannot use `#[feature(unstable)]` + //[stable]~^^ ERROR not yet stable as a const fn Foo::func(); - //[unstable]~^ ERROR not yet stable as a const fn - // ^ fails, because the `foo` feature is not active + //[unstable]~^ ERROR cannot use `#[feature(local_feature)]` + //[stable]~^^ cannot be (indirectly) exposed to stable + // We get the error on `stable` since this is a trait function. + Unstable2::func(); + //~^ ERROR not yet stable as a const fn + // ^ fails, because the `unstable2` feature is not active } #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(unstable, rustc_const_unstable(feature = "foo", issue = "none"))] +#[cfg_attr(unstable, rustc_const_unstable(feature = "local_feature", issue = "none"))] pub const fn const_context_not_const_stable() { //[stable]~^ ERROR function has missing const stability attribute Unstable::func(); //[stable]~^ ERROR not yet stable as a const fn Foo::func(); - //[unstable]~^ ERROR not yet stable as a const fn - // ^ fails, because the `foo` feature is not active + //[stable]~^ cannot be (indirectly) exposed to stable + // We get the error on `stable` since this is a trait function. + Unstable2::func(); + //~^ ERROR not yet stable as a const fn + // ^ fails, because the `unstable2` feature is not active } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "cheese", since = "1.0.0")] const fn stable_const_context() { Unstable::func(); - //~^ ERROR not yet stable as a const fn + //[unstable]~^ ERROR cannot use `#[feature(unstable)]` + //[stable]~^^ ERROR not yet stable as a const fn Foo::func(); - //[unstable]~^ ERROR not yet stable as a const fn + //[unstable]~^ ERROR cannot use `#[feature(local_feature)]` + //[stable]~^^ cannot be (indirectly) exposed to stable + // We get the error on `stable` since this is a trait function. const_context_not_const_stable() - //[unstable]~^ ERROR not yet stable as a const fn + //[unstable]~^ ERROR cannot use `#[feature(local_feature)]` } fn main() {} diff --git a/tests/ui/traits/const-traits/staged-api.stable.stderr b/tests/ui/traits/const-traits/staged-api.stable.stderr index 6c07a253f5b..40045081f93 100644 --- a/tests/ui/traits/const-traits/staged-api.stable.stderr +++ b/tests/ui/traits/const-traits/staged-api.stable.stderr @@ -1,5 +1,5 @@ error: trait implementations cannot be const stable yet - --> $DIR/staged-api.rs:21:1 + --> $DIR/staged-api.rs:22:1 | LL | / impl const MyTrait for Foo { LL | | @@ -10,40 +10,80 @@ LL | | } = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information error: function has missing const stability attribute - --> $DIR/staged-api.rs:43:1 + --> $DIR/staged-api.rs:49:1 | LL | / pub const fn const_context_not_const_stable() { LL | | LL | | Unstable::func(); LL | | ... | -LL | | // ^ fails, because the `foo` feature is not active +LL | | // ^ fails, because the `unstable2` feature is not active LL | | } | |_^ error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:34:5 + --> $DIR/staged-api.rs:35:5 | LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ | = help: add `#![feature(unstable)]` to the crate attributes to enable +error: `<Foo as staged_api::MyTrait>::func` cannot be (indirectly) exposed to stable + --> $DIR/staged-api.rs:38:5 + | +LL | Foo::func(); + | ^^^^^^^^^^^ + | + = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]` + +error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn + --> $DIR/staged-api.rs:42:5 + | +LL | Unstable2::func(); + | ^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unstable2)]` to the crate attributes to enable + error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:45:5 + --> $DIR/staged-api.rs:51:5 | LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ | = help: add `#![feature(unstable)]` to the crate attributes to enable +error: `<Foo as staged_api::MyTrait>::func` cannot be (indirectly) exposed to stable + --> $DIR/staged-api.rs:53:5 + | +LL | Foo::func(); + | ^^^^^^^^^^^ + | + = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]` + +error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn + --> $DIR/staged-api.rs:56:5 + | +LL | Unstable2::func(); + | ^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unstable2)]` to the crate attributes to enable + error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:55:5 + --> $DIR/staged-api.rs:64:5 | LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ | - = help: const-stable functions can only call other const-stable functions + = help: add `#![feature(unstable)]` to the crate attributes to enable + +error: `<Foo as staged_api::MyTrait>::func` cannot be (indirectly) exposed to stable + --> $DIR/staged-api.rs:67:5 + | +LL | Foo::func(); + | ^^^^^^^^^^^ + | + = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]` -error: aborting due to 5 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui/traits/const-traits/staged-api.unstable.stderr b/tests/ui/traits/const-traits/staged-api.unstable.stderr index 1c772f13dd5..64b3a8ab19f 100644 --- a/tests/ui/traits/const-traits/staged-api.unstable.stderr +++ b/tests/ui/traits/const-traits/staged-api.unstable.stderr @@ -1,42 +1,108 @@ -error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:36:5 +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]` + --> $DIR/staged-api.rs:35:5 | -LL | Foo::func(); - | ^^^^^^^^^^^ +LL | Unstable::func(); + | ^^^^^^^^^^^^^^^^ + | + = 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 const_context() { + | +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(unstable)] +LL | const fn const_context() { | - = help: add `#![feature(foo)]` to the crate attributes to enable -error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:47:5 +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]` + --> $DIR/staged-api.rs:38:5 | LL | Foo::func(); | ^^^^^^^^^^^ | - = help: add `#![feature(foo)]` to the crate attributes to enable + = 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 const_context() { + | +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_feature)] +LL | const fn const_context() { + | + +error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn + --> $DIR/staged-api.rs:42:5 + | +LL | Unstable2::func(); + | ^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unstable2)]` to the crate attributes to enable -error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:55:5 +error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn + --> $DIR/staged-api.rs:56:5 + | +LL | Unstable2::func(); + | ^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unstable2)]` to the crate attributes to enable + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]` + --> $DIR/staged-api.rs:64:5 | LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ | - = help: const-stable functions can only call other const-stable functions + = 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_const_context() { + | +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(unstable)] +LL | const fn stable_const_context() { + | -error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:57:5 +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]` + --> $DIR/staged-api.rs:67:5 | LL | Foo::func(); | ^^^^^^^^^^^ | - = help: const-stable functions can only call other const-stable functions + = 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_const_context() { + | +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_feature)] +LL | const fn stable_const_context() { + | -error: `const_context_not_const_stable` is not yet stable as a const fn - --> $DIR/staged-api.rs:59:5 +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]` + --> $DIR/staged-api.rs:71:5 | LL | const_context_not_const_stable() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: const-stable functions can only call other const-stable functions + = 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_const_context() { + | +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_feature)] +LL | const fn stable_const_context() { + | -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors |
