From c269d54562eb3535cbc25e5f1274c83380b96ddf Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 22 Jul 2025 14:40:01 +0000 Subject: [PATCH 1/7] Add field to distinguish const fns from always-const fns --- compiler/rustc_ast_lowering/src/item.rs | 2 +- .../src/check_consts/check.rs | 3 ++- .../rustc_const_eval/src/check_consts/ops.rs | 3 ++- .../src/const_eval/fn_queries.rs | 6 ++--- compiler/rustc_hir/src/hir.rs | 15 +++++++---- compiler/rustc_hir_pretty/src/lib.rs | 7 ++--- compiler/rustc_metadata/src/rmeta/table.rs | 3 ++- compiler/rustc_middle/src/ty/adt.rs | 3 ++- compiler/rustc_middle/src/ty/context.rs | 5 +++- .../src/ty/context/impl_interner.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 26 ++++++++++++------- compiler/rustc_mir_transform/src/lib.rs | 21 ++++++++++----- compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_passes/src/stability.rs | 4 +-- compiler/rustc_public/src/ty.rs | 4 +-- .../src/unstable/convert/internal.rs | 4 +-- .../src/unstable/convert/stable/mod.rs | 4 +-- .../src/traits/effects.rs | 18 ++++++++++--- src/librustdoc/clean/types.rs | 8 ++---- src/librustdoc/html/format.rs | 10 ++++--- 20 files changed, 93 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 3e0bc072a8d04..02755f6c31812 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1817,7 +1817,7 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_constness(&mut self, c: Const) -> hir::Constness { match c { - Const::Yes(_) => hir::Constness::Const, + Const::Yes(_) => hir::Constness::Const { always: false }, Const::No => hir::Constness::NotConst, } } diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index b66d69b924076..8cac538de4a21 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -775,7 +775,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // to do different checks than usual. trace!("attempting to call a trait method"); - let is_const = tcx.constness(callee) == hir::Constness::Const; + let is_const = + matches!(tcx.constness(callee), hir::Constness::Const { always: false }); // Only consider a trait to be const if the const conditions hold. // Otherwise, it's really misleading to call something "conditionally" diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index c776fa69ba5c1..78b23627f6b5e 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -423,7 +423,8 @@ fn build_error_for_const_call<'tcx>( err.help("const traits are not yet supported on stable Rust"); } } - } else if ccx.tcx.constness(callee) != hir::Constness::Const { + } else if !matches!(ccx.tcx.constness(callee), hir::Constness::Const { always: false }) + { let name = ccx.tcx.item_name(callee); err.span_note( ccx.tcx.def_span(callee), 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 57fd230ec4685..961292e26c2ad 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -11,13 +11,13 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Constness { let node = tcx.hir_node_by_def_id(def_id); match node { - Node::Ctor(VariantData::Tuple(..)) => Constness::Const, + Node::Ctor(VariantData::Tuple(..)) => Constness::Const { always: false }, Node::ForeignItem(item) if let ForeignItemKind::Fn(..) = item.kind => { // Foreign functions cannot be evaluated at compile-time. Constness::NotConst } Node::Expr(e) if let ExprKind::Closure(c) = e.kind => { - if let Constness::Const = c.constness && tcx.hir_body_const_context(tcx.local_parent(def_id)).is_none() { + if let Constness::Const { .. } = c.constness && tcx.hir_body_const_context(tcx.local_parent(def_id)).is_none() { tcx.dcx().span_err(tcx.def_span(def_id), "cannot use `const` closures outside of const contexts"); return Constness::NotConst; } @@ -37,7 +37,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Constness { .. }) => { match sig.header.constness { - Constness::Const => Constness::Const, + Constness::Const{always} => Constness::Const {always}, // inherent impl could be const Constness::NotConst => tcx.constness(tcx.local_parent(def_id)), } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2f18b09cf1ae8..1cb331f7909d1 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4522,17 +4522,22 @@ impl fmt::Display for Safety { } #[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable, Decodable, StableHash)] -#[derive(Default)] pub enum Constness { - #[default] - Const, + Const { always: bool }, NotConst, } +impl Default for Constness { + fn default() -> Self { + Self::Const { always: false } + } +} + impl fmt::Display for Constness { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(match *self { - Self::Const => "const", + Self::Const { always: true } => "comptime", + Self::Const { always: false } => "const", Self::NotConst => "non-const", }) } @@ -4587,7 +4592,7 @@ impl FnHeader { } pub fn is_const(&self) -> bool { - matches!(self.constness, Constness::Const) + matches!(self.constness, Constness::Const { .. }) } pub fn is_unsafe(&self) -> bool { diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 1a401af1d328d..76b9cfa115ff3 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -716,7 +716,7 @@ impl<'a> State<'a> { match of_trait { None => { - if let hir::Constness::Const = constness { + if let hir::Constness::Const { always: false } = constness { self.word_nbsp("const"); } impl_generics(self) @@ -733,7 +733,7 @@ impl<'a> State<'a> { impl_generics(self); - if let hir::Constness::Const = constness { + if let hir::Constness::Const { always: false } = constness { self.word_nbsp("const"); } @@ -2630,7 +2630,8 @@ impl<'a> State<'a> { fn print_constness(&mut self, s: hir::Constness) { match s { hir::Constness::NotConst => {} - hir::Constness::Const => self.word_nbsp("const"), + hir::Constness::Const { always: false } => self.word_nbsp("const"), + hir::Constness::Const { always: true } => { /* printed as an attribute */ } } } diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 26c5908563777..e3f40e5b17323 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -225,8 +225,9 @@ defaulted_enum! { defaulted_enum! { hir::Constness { - ( Const ) + ( Const { always: false } ) ( NotConst ) + ( Const { always: true } ) } } diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 6381a5c49835d..2aa60d558dc2d 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -310,7 +310,8 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef> for AdtDef<'tcx> { fn destructor(self, tcx: TyCtxt<'tcx>) -> Option { Some(match tcx.constness(self.destructor(tcx)?.did) { - hir::Constness::Const => AdtDestructorKind::Const, + hir::Constness::Const { always: true } => todo!("FIXME(comptime)"), + hir::Constness::Const { always: false } => AdtDestructorKind::Const, hir::Constness::NotConst => AdtDestructorKind::NotConst, }) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 6c68a83f9357a..2f0c9d98e25b7 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2645,7 +2645,10 @@ impl<'tcx> TyCtxt<'tcx> { /// Whether the trait impl is marked const. This does not consider stability or feature gates. pub fn is_const_trait_impl(self, def_id: DefId) -> bool { self.def_kind(def_id) == DefKind::Impl { of_trait: true } - && self.impl_trait_header(def_id).constness == hir::Constness::Const + && matches!( + self.impl_trait_header(def_id).constness, + hir::Constness::Const { always: false } + ) } pub fn is_sdylib_interface_build(self) -> bool { diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 6f6317d53d97b..9a53c1df608a2 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -403,7 +403,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn closure_is_const(self, def_id: DefId) -> bool { debug_assert_matches!(self.def_kind(def_id), DefKind::Closure); - self.constness(def_id) == hir::Constness::Const + matches!(self.constness(def_id), hir::Constness::Const { always: false }) } fn alias_has_const_conditions(self, def_id: DefId) -> bool { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 93da73e1e4505..858c6374ca044 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2076,7 +2076,7 @@ impl<'tcx> TyCtxt<'tcx> { matches!( self.def_kind(def_id), DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Closure - ) && self.constness(def_id) == hir::Constness::Const + ) && matches!(self.constness(def_id), hir::Constness::Const { .. }) } /// Whether this item is conditionally constant for the purposes of the @@ -2090,12 +2090,14 @@ impl<'tcx> TyCtxt<'tcx> { match self.def_kind(def_id) { DefKind::Impl { of_trait: true } => { let header = self.impl_trait_header(def_id); - header.constness == hir::Constness::Const + matches!(header.constness, hir::Constness::Const { always: false }) && self.is_const_trait(header.trait_ref.skip_binder().def_id) } - DefKind::Impl { of_trait: false } => self.constness(def_id) == hir::Constness::Const, + DefKind::Impl { of_trait: false } => { + matches!(self.constness(def_id), hir::Constness::Const { always: false }) + } DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) => { - self.constness(def_id) == hir::Constness::Const + matches!(self.constness(def_id), hir::Constness::Const { always: false }) } DefKind::TraitAlias | DefKind::Trait => self.is_const_trait(def_id), DefKind::AssocTy => { @@ -2112,17 +2114,19 @@ impl<'tcx> TyCtxt<'tcx> { let parent_def_id = self.parent(def_id); match self.def_kind(parent_def_id) { DefKind::Impl { of_trait: false } => { - self.constness(def_id) == hir::Constness::Const + matches!(self.constness(def_id), hir::Constness::Const { always: false }) } DefKind::Impl { of_trait: true } => { let Some(trait_method_did) = self.trait_item_of(def_id) else { return false; }; - self.constness(trait_method_did) == hir::Constness::Const - && self.is_conditionally_const(parent_def_id) + matches!( + self.constness(trait_method_did), + hir::Constness::Const { always: false } + ) && self.is_conditionally_const(parent_def_id) } DefKind::Trait => { - self.constness(def_id) == hir::Constness::Const + matches!(self.constness(def_id), hir::Constness::Const { always: false }) && self.is_conditionally_const(parent_def_id) } _ => bug!("unexpected parent item of associated fn: {parent_def_id:?}"), @@ -2134,7 +2138,9 @@ impl<'tcx> TyCtxt<'tcx> { // FIXME(const_trait_impl): ATPITs could be conditionally const? hir::OpaqueTyOrigin::TyAlias { .. } => false, }, - DefKind::Closure => self.constness(def_id) == hir::Constness::Const, + DefKind::Closure => { + matches!(self.constness(def_id), hir::Constness::Const { always: false }) + } DefKind::Ctor(_, CtorKind::Const) | DefKind::Mod | DefKind::Struct @@ -2163,7 +2169,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn is_const_trait(self, def_id: DefId) -> bool { - self.trait_def(def_id).constness == hir::Constness::Const + matches!(self.trait_def(def_id).constness, hir::Constness::Const { .. }) } pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool { diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 91dfffcf1a6a5..4f7960cd5bb6d 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -261,8 +261,13 @@ fn remap_mir_for_const_eval_select<'tcx>( let ty = tupled_args.node.ty(&body.local_decls, tcx); let fields = ty.tuple_fields(); let num_args = fields.len(); - let func = - if context == hir::Constness::Const { called_in_const } else { called_at_rt }; + let func = match context { + hir::Constness::Const { always: false } => called_in_const, + hir::Constness::Const { always: true } => { + todo!("should not use `const_eval_select` in always-const code") + } + hir::Constness::NotConst => called_at_rt, + }; let (method, place): (fn(Place<'tcx>) -> Operand<'tcx>, Place<'tcx>) = match tupled_args.node { Operand::Constant(_) | Operand::RuntimeChecks(_) => { @@ -437,7 +442,7 @@ fn mir_promoted( let const_qualifs = match tcx.def_kind(def) { DefKind::Fn | DefKind::AssocFn | DefKind::Closure - if tcx.constness(def) == hir::Constness::Const => + if matches!(tcx.constness(def), hir::Constness::Const { .. }) => { tcx.mir_const_qualif(def) } @@ -501,15 +506,17 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> { } let body = tcx.mir_drops_elaborated_and_const_checked(def); - let body = match tcx.hir_body_const_context(def) { + let (body, always) = match tcx.hir_body_const_context(def) { // consts and statics do not have `optimized_mir`, so we can steal the body instead of // cloning it. - Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => body.steal(), - Some(hir::ConstContext::ConstFn) => body.borrow().clone(), + Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => { + (body.steal(), true) + } + Some(hir::ConstContext::ConstFn) => (body.borrow().clone(), false), None => bug!("`mir_for_ctfe` called on non-const {def:?}"), }; - let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::Const); + let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::Const { always }); pm::run_passes(tcx, &mut body, &[&ctfe_limit::CtfeLimit], None, pm::Optimizations::Allowed); body diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3331fd537ef93..566e55beb0f24 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -540,7 +540,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if target == (Target::Impl { of_trait: true }) { match item.unwrap() { ItemLike::Item(it) => match it.expect_impl().constness { - Constness::Const => { + Constness::Const { .. } => { let item_span = self.tcx.hir_span(hir_id); self.tcx.emit_node_span_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index e41df43e34bd3..b67bac166c12e 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -651,7 +651,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { } if features.const_trait_impl() - && let hir::Constness::Const = constness + && let hir::Constness::Const { .. } = constness { let stable_or_implied_stable = match const_stab { None => true, @@ -695,7 +695,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { } } - if let hir::Constness::Const = constness + if let hir::Constness::Const { .. } = constness && let Some(def_id) = of_trait.trait_ref.trait_def_id() { // FIXME(const_trait_impl): Improve the span here. diff --git a/compiler/rustc_public/src/ty.rs b/compiler/rustc_public/src/ty.rs index 59b4c6bee5c03..9eeceb7cb0832 100644 --- a/compiler/rustc_public/src/ty.rs +++ b/compiler/rustc_public/src/ty.rs @@ -1117,13 +1117,13 @@ impl FnSig { #[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum Constness { - Const, + Const { always: bool }, NotConst, } impl Constness { pub fn is_const(self) -> bool { - matches!(self, Constness::Const) + matches!(self, Constness::Const { always: false }) } } diff --git a/compiler/rustc_public/src/unstable/convert/internal.rs b/compiler/rustc_public/src/unstable/convert/internal.rs index 165ad737fccb8..b7d968a29ae86 100644 --- a/compiler/rustc_public/src/unstable/convert/internal.rs +++ b/compiler/rustc_public/src/unstable/convert/internal.rs @@ -646,8 +646,8 @@ impl RustcInternal for Constness { _tables: &mut Tables<'_, BridgeTys>, _tcx: impl InternalCx<'tcx>, ) -> Self::T<'tcx> { - match self { - Constness::Const => rustc_hir::Constness::Const, + match *self { + Constness::Const { always } => rustc_hir::Constness::Const { always }, Constness::NotConst => rustc_hir::Constness::NotConst, } } diff --git a/compiler/rustc_public/src/unstable/convert/stable/mod.rs b/compiler/rustc_public/src/unstable/convert/stable/mod.rs index ce55e898b2acb..083a30adab13f 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mod.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mod.rs @@ -24,8 +24,8 @@ impl<'tcx> Stable<'tcx> for rustc_hir::Safety { impl<'tcx> Stable<'tcx> for rustc_hir::Constness { type T = crate::ty::Constness; fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &CompilerCtxt<'_, BridgeTys>) -> Self::T { - match self { - rustc_hir::Constness::Const => crate::ty::Constness::Const, + match *self { + rustc_hir::Constness::Const { always } => crate::ty::Constness::Const { always }, rustc_hir::Constness::NotConst => crate::ty::Constness::NotConst, } } diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index 0f36edcdd830e..0534f5e8e4036 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -461,10 +461,11 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( .map(|field| ty::TraitRef::new(tcx, destruct_def_id, [field.ty(tcx, args)])) .collect(); match adt_def.destructor(tcx).map(|dtor| tcx.constness(dtor.did)) { + Some(hir::Constness::Const { always: true }) => todo!("FIXME(comptime)"), // `Drop` impl exists, but it's not const. Type cannot be `[const] Destruct`. Some(hir::Constness::NotConst) => return Err(EvaluationFailure::NoSolution), // `Drop` impl exists, and it's const. Require `Ty: [const] Drop` to hold. - Some(hir::Constness::Const) => { + Some(hir::Constness::Const { always: false }) => { let drop_def_id = tcx.require_lang_item(LangItem::Drop, obligation.cause.span); let drop_trait_ref = ty::TraitRef::new(tcx, drop_def_id, [self_ty]); const_conditions.push(drop_trait_ref); @@ -561,7 +562,9 @@ fn evaluate_host_effect_for_fn_goal<'tcx>( }; match tcx.constness(def) { - hir::Constness::Const => Ok(tcx + // FIXME(comptime) + hir::Constness::Const { always: true } => Err(EvaluationFailure::NoSolution), + hir::Constness::Const { always: false } => Ok(tcx .const_conditions(def) .instantiate(tcx, args) .into_iter() @@ -592,8 +595,15 @@ fn evaluate_host_effect_from_selection_candidate<'tcx>( Err(_) => Err(EvaluationFailure::NoSolution), Ok(Some(source)) => match source { ImplSource::UserDefined(impl_) => { - if tcx.impl_trait_header(impl_.impl_def_id).constness != hir::Constness::Const { - return Err(EvaluationFailure::NoSolution); + match tcx.impl_trait_header(impl_.impl_def_id).constness { + rustc_hir::Constness::Const { always } => { + if always { + todo!() + } + } + rustc_hir::Constness::NotConst => { + return Err(EvaluationFailure::NoSolution); + } } let mut nested = impl_.nested; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 05d4888c110cc..a18396379e78e 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -790,7 +790,7 @@ impl Item { { hir::Constness::NotConst } else { - hir::Constness::Const + hir::Constness::Const { always: false } } } else { hir::Constness::NotConst @@ -821,11 +821,7 @@ impl Item { safety.into() }, abi, - constness: if tcx.is_const_fn(def_id) { - hir::Constness::Const - } else { - hir::Constness::NotConst - }, + constness: hir::Constness::NotConst, asyncness: hir::IsAsync::NotAsync, } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 0694dd05cd399..91214b5d06412 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1490,15 +1490,19 @@ pub(crate) fn print_constness_with_space( overall_stab: Option, const_stab: Option, ) -> &'static str { - match c { - hir::Constness::Const => match (overall_stab, const_stab) { + match *c { + hir::Constness::Const { always } => match (overall_stab, const_stab) { // const stable... (_, Some(ConstStability { level: StabilityLevel::Stable { .. }, .. })) // ...or when feature(staged_api) is not set... | (_, None) // ...or when const unstable, but overall unstable too | (None, Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. })) => { - "const " + if always { + "" + } else { + "const " + } } // const unstable (and overall stable) (Some(_), Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. })) => "", From 61ba7f583bf376fbd7aca09c066c6f12e3d0f61e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 23 Jul 2025 10:33:12 +0000 Subject: [PATCH 2/7] Check comptime fns --- compiler/rustc_ast_lowering/src/errors.rs | 11 ++++++++ compiler/rustc_ast_lowering/src/item.rs | 22 ++++++++++++---- .../src/attributes/semantics.rs | 11 ++++++++ compiler/rustc_attr_parsing/src/context.rs | 3 ++- compiler/rustc_feature/src/builtin_attrs.rs | 4 +++ .../rustc_hir/src/attrs/data_structures.rs | 3 +++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + tests/ui/README.md | 4 +++ tests/ui/comptime/const_comptime.rs | 7 +++++ tests/ui/comptime/const_comptime.stderr | 16 ++++++++++++ tests/ui/comptime/not_callable.rs | 25 ++++++++++++++++++ tests/ui/comptime/trait_comptime.rs | 26 +++++++++++++++++++ tests/ui/comptime/trait_comptime.stderr | 26 +++++++++++++++++++ 15 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 tests/ui/comptime/const_comptime.rs create mode 100644 tests/ui/comptime/const_comptime.stderr create mode 100644 tests/ui/comptime/not_callable.rs create mode 100644 tests/ui/comptime/trait_comptime.rs create mode 100644 tests/ui/comptime/trait_comptime.stderr diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 95b8bb48c6a9c..e9e940ec2673b 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -3,6 +3,17 @@ use rustc_errors::{DiagArgFromDisplay, DiagSymbolList}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; +#[derive(Diagnostic)] +#[diag("a function cannot be both `comptime` and `const`")] +pub(crate) struct ConstComptimeFn { + #[primary_span] + #[suggestion("remove the `const`", applicability = "machine-applicable", code = "")] + #[note("`const` implies the function can be called at runtime, too")] + pub span: Span, + #[label("`comptime` because of this")] + pub attr_span: Span, +} + #[derive(Diagnostic)] #[diag("parenthesized type parameters may only be used with a `Fn` trait", code = E0214)] pub(crate) struct GenericTypeWithParentheses { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 02755f6c31812..62da9f1a51a5b 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -25,6 +25,7 @@ use super::{ AstOwner, FnDeclKind, GenericArgsMode, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt, }; +use crate::errors::ConstComptimeFn; /// Wraps either IndexVec (during `hir_crate`), which acts like a primary /// storage for most of the MaybeOwners, or FxIndexMap during delayed AST -> HIR @@ -1750,12 +1751,23 @@ impl<'hir> LoweringContext<'_, 'hir> { safety.into() }; - hir::FnHeader { - safety, - asyncness, - constness: self.lower_constness(h.constness), - abi: self.lower_extern(h.ext), + let mut constness = self.lower_constness(h.constness); + if let Some(&attr_span) = find_attr!(attrs, Comptime(span) => span) { + match std::mem::replace(&mut constness, rustc_hir::Constness::Const { always: true }) { + rustc_hir::Constness::Const { always: true } => { + unreachable!("lower_constness cannot produce comptime") + } + // A function can't be `const` and `comptime` at the same time + rustc_hir::Constness::Const { always: false } => { + let Const::Yes(span) = h.constness else { unreachable!() }; + self.dcx().emit_err(ConstComptimeFn { span, attr_span }); + } + // Good + rustc_hir::Constness::NotConst => {} + } } + + hir::FnHeader { safety, asyncness, constness, abi: self.lower_extern(h.ext) } } pub(super) fn lower_abi(&mut self, abi_str: StrLit) -> ExternAbi { diff --git a/compiler/rustc_attr_parsing/src/attributes/semantics.rs b/compiler/rustc_attr_parsing/src/attributes/semantics.rs index b5c836e6119dc..93e775480fdbe 100644 --- a/compiler/rustc_attr_parsing/src/attributes/semantics.rs +++ b/compiler/rustc_attr_parsing/src/attributes/semantics.rs @@ -6,3 +6,14 @@ impl NoArgsAttributeParser for MayDangleParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs` const CREATE: fn(span: Span) -> AttributeKind = AttributeKind::MayDangle; } + +pub(crate) struct ComptimeParser; +impl NoArgsAttributeParser for ComptimeParser { + const PATH: &[Symbol] = &[sym::rustc_comptime]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Fn), + ]); + const CREATE: fn(Span) -> AttributeKind = AttributeKind::Comptime; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 9fc7c3c8f1320..2162f5e7715f7 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -53,7 +53,7 @@ use crate::attributes::repr::*; use crate::attributes::rustc_allocator::*; use crate::attributes::rustc_dump::*; use crate::attributes::rustc_internal::*; -use crate::attributes::semantics::*; +use crate::attributes::semantics::{ComptimeParser, *}; use crate::attributes::stability::*; use crate::attributes::test_attrs::*; use crate::attributes::traits::*; @@ -231,6 +231,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 053caee258f7b..24feb34d67cec 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -746,6 +746,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_no_writable, "`#[rustc_no_writable]` stops the compiler from considering mutable reference arguments of this function as implicitly writable" ), + rustc_attr!( + rustc_comptime, + "the `#[rustc_comptime]` attribute is just used to avoid adding syntax for `comptime fn`" + ), // ========================================================================== // Internal attributes, Testing: diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index ffee84f4ed8b2..3d7762aae618f 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -967,6 +967,9 @@ pub enum AttributeKind { /// Represents `#[compiler_builtins]`. CompilerBuiltins, + /// Represents `#[rustc_comptime]` + Comptime(Span), + /// Represents `#[const_continue]`. ConstContinue(Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index c98e1a0a3cbaa..45e381d273f84 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -27,6 +27,7 @@ impl AttributeKind { Cold => No, CollapseDebugInfo(..) => Yes, CompilerBuiltins => No, + Comptime(..) => No, ConstContinue(..) => No, Coroutine => No, Coverage(..) => No, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 566e55beb0f24..66c41b6462909 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -214,6 +214,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::Cold | AttributeKind::CollapseDebugInfo(..) | AttributeKind::CompilerBuiltins + | AttributeKind::Comptime(..) | AttributeKind::Coroutine | AttributeKind::Coverage (..) | AttributeKind::CrateName { .. } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ddfe05e5c607d..83a39c9afe345 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1714,6 +1714,7 @@ symbols! { rustc_clean, rustc_coherence_is_core, rustc_coinductive, + rustc_comptime, rustc_confusables, rustc_const_stable, rustc_const_stable_indirect, diff --git a/tests/ui/README.md b/tests/ui/README.md index 2fe1657e7ecf2..4365f5082dbb6 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -292,6 +292,10 @@ Tests for compile flags. Meta test suite of the test harness `compiletest` itself. +## `tests/ui/comptime`: compile-time only functions and intrinsics + +Test the `#[rustc_comptime]` attribute and intrinsics that inherently can only run at compile-time. + ## `tests/ui/conditional-compilation/`: Conditional Compilation Tests for `#[cfg]` attribute or `--cfg` flags, used to compile certain files or code blocks only if certain conditions are met (such as developing on a specific architecture). diff --git a/tests/ui/comptime/const_comptime.rs b/tests/ui/comptime/const_comptime.rs new file mode 100644 index 0000000000000..827e4dfcf545b --- /dev/null +++ b/tests/ui/comptime/const_comptime.rs @@ -0,0 +1,7 @@ +#![feature(rustc_attrs)] + +#[rustc_comptime] +const fn foo() {} +//~^ ERROR a function cannot be both `comptime` and `const` + +fn main() {} diff --git a/tests/ui/comptime/const_comptime.stderr b/tests/ui/comptime/const_comptime.stderr new file mode 100644 index 0000000000000..8be8ee7d69a1d --- /dev/null +++ b/tests/ui/comptime/const_comptime.stderr @@ -0,0 +1,16 @@ +error: a function cannot be both `comptime` and `const` + --> $DIR/const_comptime.rs:4:1 + | +LL | #[rustc_comptime] + | ----------------- `comptime` because of this +LL | const fn foo() {} + | ^^^^^ help: remove the `const` + | +note: `const` implies the function can be called at runtime, too + --> $DIR/const_comptime.rs:4:1 + | +LL | const fn foo() {} + | ^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/comptime/not_callable.rs b/tests/ui/comptime/not_callable.rs new file mode 100644 index 0000000000000..ce454ef5222e2 --- /dev/null +++ b/tests/ui/comptime/not_callable.rs @@ -0,0 +1,25 @@ +#![feature(rustc_attrs)] + +//TODO: should fail +//@check-pass + +#[rustc_comptime] +fn foo() {} + +fn main() { + // Ok + const { foo() }; + // TODO: Not ok + foo(); +} + +const fn bar() { + // TODO: Not ok + foo(); +} + +#[rustc_comptime] +fn baz() { + // Should be allowed + foo(); +} diff --git a/tests/ui/comptime/trait_comptime.rs b/tests/ui/comptime/trait_comptime.rs new file mode 100644 index 0000000000000..a42e85c49f702 --- /dev/null +++ b/tests/ui/comptime/trait_comptime.rs @@ -0,0 +1,26 @@ +#![feature(rustc_attrs)] + +trait Foo { + #[rustc_comptime] + //~^ ERROR: cannot be used on required trait methods + fn foo(); + + #[rustc_comptime] + //~^ ERROR: cannot be used on provided trait methods + fn bar() {} +} + +struct Bar; + +impl Bar { + #[rustc_comptime] + fn foo() {} +} + +impl Foo for Bar { + #[rustc_comptime] + //~^ ERROR: cannot be used on trait methods + fn foo() {} +} + +fn main() {} diff --git a/tests/ui/comptime/trait_comptime.stderr b/tests/ui/comptime/trait_comptime.stderr new file mode 100644 index 0000000000000..77ff09674d2bd --- /dev/null +++ b/tests/ui/comptime/trait_comptime.stderr @@ -0,0 +1,26 @@ +error: `#[rustc_comptime]` attribute cannot be used on required trait methods + --> $DIR/trait_comptime.rs:4:5 + | +LL | #[rustc_comptime] + | ^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_comptime]` can be applied to functions and inherent methods + +error: `#[rustc_comptime]` attribute cannot be used on provided trait methods + --> $DIR/trait_comptime.rs:8:5 + | +LL | #[rustc_comptime] + | ^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_comptime]` can be applied to functions and inherent methods + +error: `#[rustc_comptime]` attribute cannot be used on trait methods in impl blocks + --> $DIR/trait_comptime.rs:21:5 + | +LL | #[rustc_comptime] + | ^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_comptime]` can be applied to functions and inherent methods + +error: aborting due to 3 previous errors + From fbce62688fda9f29217f755a198d7a39bc6a84f3 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 5 Nov 2025 16:32:38 +0000 Subject: [PATCH 3/7] Prevent comptime fns from being called at runtime --- compiler/rustc_hir_typeck/src/callee.rs | 13 ++++++++++++- tests/ui/comptime/not_callable.rs | 17 +++++++---------- tests/ui/comptime/not_callable.stderr | 20 ++++++++++++++++++++ 3 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 tests/ui/comptime/not_callable.stderr diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index fc504116101c9..3f0f16900eebf 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -919,6 +919,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { callee_did: DefId, callee_args: GenericArgsRef<'tcx>, ) { + let const_context = self.tcx.hir_body_const_context(self.body_id); + + if let hir::Constness::Const { always: true } = self.tcx.constness(callee_did) { + match const_context { + Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => {} + Some(hir::ConstContext::ConstFn) | None => { + self.dcx().span_err(span, "comptime fns can only be called at compile time"); + } + } + } + // FIXME(const_trait_impl): We should be enforcing these effects unconditionally. // This can be done as soon as we convert the standard library back to // using const traits, since if we were to enforce these conditions now, @@ -932,7 +943,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - let host = match self.tcx.hir_body_const_context(self.body_id) { + let host = match const_context { Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => { ty::BoundConstness::Const } diff --git a/tests/ui/comptime/not_callable.rs b/tests/ui/comptime/not_callable.rs index ce454ef5222e2..d0da9615313b3 100644 --- a/tests/ui/comptime/not_callable.rs +++ b/tests/ui/comptime/not_callable.rs @@ -1,7 +1,4 @@ -#![feature(rustc_attrs)] - -//TODO: should fail -//@check-pass +#![feature(rustc_attrs, const_trait_impl)] #[rustc_comptime] fn foo() {} @@ -9,17 +6,17 @@ fn foo() {} fn main() { // Ok const { foo() }; - // TODO: Not ok - foo(); + // Not Ok + foo(); //~ ERROR: comptime fns can only be called at compile time } const fn bar() { - // TODO: Not ok - foo(); + // Not Ok + foo(); //~ ERROR: comptime fns can only be called at compile time } #[rustc_comptime] fn baz() { - // Should be allowed - foo(); + // TODO: Should be allowed + foo(); //~ ERROR: comptime fns can only be called at compile time } diff --git a/tests/ui/comptime/not_callable.stderr b/tests/ui/comptime/not_callable.stderr new file mode 100644 index 0000000000000..2aeb9bca740cc --- /dev/null +++ b/tests/ui/comptime/not_callable.stderr @@ -0,0 +1,20 @@ +error: comptime fns can only be called at compile time + --> $DIR/not_callable.rs:10:5 + | +LL | foo(); + | ^^^^^ + +error: comptime fns can only be called at compile time + --> $DIR/not_callable.rs:15:5 + | +LL | foo(); + | ^^^^^ + +error: comptime fns can only be called at compile time + --> $DIR/not_callable.rs:21:5 + | +LL | foo(); + | ^^^^^ + +error: aborting due to 3 previous errors + From bb3d6c51d81529dc5cd73f76d28fb33afb62a5f3 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 5 Nov 2025 16:55:03 +0000 Subject: [PATCH 4/7] Allow comptime fns to call other comptime fns --- compiler/rustc_middle/src/hir/map.rs | 8 +++++++- tests/ui/comptime/not_callable.rs | 4 ++-- tests/ui/comptime/not_callable.stderr | 8 +------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 37273928d7d1f..14fc09a51838d 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -321,7 +321,13 @@ impl<'tcx> TyCtxt<'tcx> { BodyOwnerKind::Closure if self.is_const_fn(def_id) => { return self.hir_body_const_context(self.local_parent(local_def_id)); } - BodyOwnerKind::Fn if self.is_const_fn(def_id) => ConstContext::ConstFn, + BodyOwnerKind::Fn if self.is_const_fn(def_id) => { + if matches!(self.constness(def_id), rustc_hir::Constness::Const { always: true }) { + ConstContext::Const { inline: true } + } else { + ConstContext::ConstFn + } + } BodyOwnerKind::Fn | BodyOwnerKind::Closure | BodyOwnerKind::GlobalAsm => return None, }; diff --git a/tests/ui/comptime/not_callable.rs b/tests/ui/comptime/not_callable.rs index d0da9615313b3..c06e643d5403e 100644 --- a/tests/ui/comptime/not_callable.rs +++ b/tests/ui/comptime/not_callable.rs @@ -17,6 +17,6 @@ const fn bar() { #[rustc_comptime] fn baz() { - // TODO: Should be allowed - foo(); //~ ERROR: comptime fns can only be called at compile time + // Ok + foo(); } diff --git a/tests/ui/comptime/not_callable.stderr b/tests/ui/comptime/not_callable.stderr index 2aeb9bca740cc..8a2c3fb2bf00f 100644 --- a/tests/ui/comptime/not_callable.stderr +++ b/tests/ui/comptime/not_callable.stderr @@ -10,11 +10,5 @@ error: comptime fns can only be called at compile time LL | foo(); | ^^^^^ -error: comptime fns can only be called at compile time - --> $DIR/not_callable.rs:21:5 - | -LL | foo(); - | ^^^^^ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors From beed5c7bdfc0f59c636718fb1253f3c2c9f7c1a2 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 11 Nov 2025 12:13:50 +0000 Subject: [PATCH 5/7] Demonstrate that `const Trait` bounds allow trait methods to be called in comptime fn --- tests/ui/comptime/trait_bounds.rs | 25 +++++++++++++++++++++++++ tests/ui/comptime/trait_bounds.stderr | 27 +++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 tests/ui/comptime/trait_bounds.rs create mode 100644 tests/ui/comptime/trait_bounds.stderr diff --git a/tests/ui/comptime/trait_bounds.rs b/tests/ui/comptime/trait_bounds.rs new file mode 100644 index 0000000000000..3df2f41558fcc --- /dev/null +++ b/tests/ui/comptime/trait_bounds.rs @@ -0,0 +1,25 @@ +#![feature(rustc_attrs, const_trait_impl)] + +const trait Trait { + fn method() {} +} + +#[rustc_comptime] +fn always_const() { + T::method() +} + +#[rustc_comptime] +fn conditionally_const() { + //~^ ERROR: `[const]` is not allowed here + T::method() + //~^ ERROR: `T: const Trait` is not satisfied +} + +#[rustc_comptime] +fn non_const() { + T::method() + //~^ ERROR: `T: const Trait` is not satisfied +} + +fn main() {} diff --git a/tests/ui/comptime/trait_bounds.stderr b/tests/ui/comptime/trait_bounds.stderr new file mode 100644 index 0000000000000..c5a03af2c0c2c --- /dev/null +++ b/tests/ui/comptime/trait_bounds.stderr @@ -0,0 +1,27 @@ +error: `[const]` is not allowed here + --> $DIR/trait_bounds.rs:13:27 + | +LL | fn conditionally_const() { + | ^^^^^^^ + | +note: this function is not `const`, so it cannot have `[const]` trait bounds + --> $DIR/trait_bounds.rs:13:4 + | +LL | fn conditionally_const() { + | ^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `T: const Trait` is not satisfied + --> $DIR/trait_bounds.rs:15:5 + | +LL | T::method() + | ^ + +error[E0277]: the trait bound `T: const Trait` is not satisfied + --> $DIR/trait_bounds.rs:21:5 + | +LL | T::method() + | ^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. From ddb9e59cf84c66c00af69f4e9629d30d28f4acca Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 11 Nov 2025 12:30:42 +0000 Subject: [PATCH 6/7] Make the `inline` field on the `Const` `ConstContext` more clearly targetted at what it does --- compiler/rustc_hir/src/hir.rs | 10 ++++++---- compiler/rustc_middle/src/hir/map.rs | 6 ++++-- compiler/rustc_mir_transform/src/promote_consts.rs | 5 ++++- .../clippy_lints/src/default_numeric_fallback.rs | 2 +- src/tools/clippy/clippy_utils/src/lib.rs | 2 +- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 1cb331f7909d1..d709393e66917 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2355,10 +2355,12 @@ pub enum ConstContext { /// - Array length expressions /// - Enum discriminants /// - Const generics - /// - /// For the most part, other contexts are treated just like a regular `const`, so they are - /// lumped into the same category. - Const { inline: bool }, + Const { + /// For backwards compatibility `const` items allow + /// calls to `const fn` to get promoted. + /// We forbid that in comptime fns and inline consts. + allow_const_fn_promotion: bool, + }, } impl ConstContext { diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 14fc09a51838d..7f5b633efc375 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -313,7 +313,9 @@ impl<'tcx> TyCtxt<'tcx> { pub fn hir_body_const_context(self, local_def_id: LocalDefId) -> Option { let def_id = local_def_id.into(); let ccx = match self.hir_body_owner_kind(def_id) { - BodyOwnerKind::Const { inline } => ConstContext::Const { inline }, + BodyOwnerKind::Const { inline } => { + ConstContext::Const { allow_const_fn_promotion: !inline } + } BodyOwnerKind::Static(mutability) => ConstContext::Static(mutability), BodyOwnerKind::Fn if self.is_constructor(def_id) => return None, @@ -323,7 +325,7 @@ impl<'tcx> TyCtxt<'tcx> { } BodyOwnerKind::Fn if self.is_const_fn(def_id) => { if matches!(self.constness(def_id), rustc_hir::Constness::Const { always: true }) { - ConstContext::Const { inline: true } + ConstContext::Const { allow_const_fn_promotion: false } } else { ConstContext::ConstFn } diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 041ff45c11d7e..9e40af7de23e0 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -657,7 +657,10 @@ impl<'tcx> Validator<'_, 'tcx> { // backwards compatibility reason to allow more promotion inside of them. let promote_all_fn = matches!( self.const_kind, - Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { inline: false }) + Some( + hir::ConstContext::Static(_) + | hir::ConstContext::Const { allow_const_fn_promotion: true } + ) ); if !promote_all_fn { return Err(Unpromotable); diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index 4324a8465be6f..1c377b7faf6cf 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback { // Inline const supports type inference. let is_parent_const = matches!( cx.tcx.hir_body_const_context(cx.tcx.hir_body_owner_def_id(body.id())), - Some(ConstContext::Const { inline: false } | ConstContext::Static(_)) + Some(ConstContext::Const { allow_const_fn_promotion: true } | ConstContext::Static(_)) ); let mut visitor = NumericFallbackVisitor::new(cx, is_parent_const); visitor.visit_body(body); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index b7c08c380903f..a0de0f52ef991 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -243,7 +243,7 @@ pub fn is_inside_always_const_context(tcx: TyCtxt<'_>, hir_id: HirId) -> bool { }; match ctx { ConstFn => false, - Static(_) | Const { inline: _ } => true, + Static(_) | Const { allow_const_fn_promotion: _ } => true, } } From d092d4ea30fe0e5033b1a43f9e9119b1f533a258 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sun, 3 May 2026 11:52:43 +0200 Subject: [PATCH 7/7] Remove possibly footgunny `is_const` method --- compiler/rustc_hir/src/hir.rs | 4 ---- compiler/rustc_passes/src/stability.rs | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index d709393e66917..0e58ed5f798d9 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4593,10 +4593,6 @@ impl FnHeader { matches!(self.asyncness, IsAsync::Async(_)) } - pub fn is_const(&self) -> bool { - matches!(self.constness, Constness::Const { .. }) - } - pub fn is_unsafe(&self) -> bool { self.safety().is_unsafe() } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index b67bac166c12e..f5c2ea8264900 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -206,7 +206,7 @@ fn lookup_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option, def_id: LocalDefId) -> Option MissingStabilityAnnotations<'tcx> { // implied), check if the function/method is const or the parent impl block is const. let fn_sig = self.tcx.hir_node_by_def_id(def_id).fn_sig(); if let Some(fn_sig) = fn_sig - && !fn_sig.header.is_const() + && !matches!(fn_sig.header.constness, Constness::Const { .. }) && const_stab.is_some() && find_attr_span!(RustcConstStability).is_some() {