From f3a735cf3187b2f041dd20a0285ee8993bd2db51 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 9 Jun 2026 17:24:00 +0200 Subject: [PATCH] Require `rustc_comptime` fns to also be `const` --- .../rustc_ast_lowering/src/diagnostics.rs | 10 +++-- compiler/rustc_ast_lowering/src/item.rs | 37 +++++++++---------- tests/ui/comptime/const_comptime.rs | 4 +- tests/ui/comptime/const_comptime.stderr | 12 +++--- tests/ui/comptime/feature-gate-test.rs | 2 +- tests/ui/comptime/not_callable.rs | 4 +- tests/ui/comptime/trait_bounds.rs | 7 ++-- tests/ui/comptime/trait_bounds.stderr | 18 ++------- tests/ui/comptime/trait_comptime.rs | 11 ++++-- tests/ui/comptime/trait_comptime.stderr | 34 +++++++++++++++-- 10 files changed, 79 insertions(+), 60 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/diagnostics.rs b/compiler/rustc_ast_lowering/src/diagnostics.rs index 31f094209a946..95bfd9345843f 100644 --- a/compiler/rustc_ast_lowering/src/diagnostics.rs +++ b/compiler/rustc_ast_lowering/src/diagnostics.rs @@ -123,11 +123,13 @@ pub(crate) struct AwaitOnlyInAsyncFnAndBlocks { } #[derive(Diagnostic)] -#[diag("a function cannot be both `comptime` and `const`")] -pub(crate) struct ConstComptimeFn { +#[diag("a function cannot just be `comptime`")] +pub(crate) struct NonConstComptimeFn { #[primary_span] - #[suggestion("remove the `const`", applicability = "machine-applicable", code = "")] - #[note("`const` implies the function can be called at runtime, too")] + #[suggestion("add `const`", applicability = "machine-applicable", code = "const ")] + #[note( + "`const` is less restrictive than `comptime`, but already adds many restrictions `comptime` needs" + )] pub span: Span, #[label("`comptime` because of this")] pub attr_span: Span, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 336c644961ab6..6dc6e5247b0fc 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -27,7 +27,7 @@ use super::{ AstOwner, FnDeclKind, GenericArgsMode, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt, }; -use crate::diagnostics::ConstComptimeFn; +use crate::diagnostics::NonConstComptimeFn; /// Wraps either IndexVec (during `hir_crate`), which acts like a primary /// storage for most of the MaybeOwners, or FxIndexMap during delayed AST -> HIR @@ -353,15 +353,8 @@ impl<'hir> LoweringContext<'_, 'hir> { self.record_body(&[], body) }), ), - ItemKind::Fn(Fn { - sig: FnSig { decl, header, span: fn_sig_span }, - ident, - generics, - body, - contract, - define_opaque, - .. - }) => { + ItemKind::Fn(Fn { sig, ident, generics, body, contract, define_opaque, .. }) => { + let FnSig { decl, header, span: fn_sig_span } = sig; self.with_new_scopes(*fn_sig_span, |this| { // Note: we don't need to change the return type from `T` to // `impl Future` here because lower_body @@ -385,7 +378,12 @@ impl<'hir> LoweringContext<'_, 'hir> { }); let sig = hir::FnSig { decl, - header: this.lower_fn_header(*header, hir::Safety::Safe, attrs), + header: this.lower_fn_header( + *header, + sig.header_span(), + hir::Safety::Safe, + attrs, + ), span: this.lower_span(*fn_sig_span), }; this.lower_define_opaque(hir_id, define_opaque); @@ -808,7 +806,8 @@ impl<'hir> LoweringContext<'_, 'hir> { }); // Unmarked safety in unsafe block defaults to unsafe. - let header = self.lower_fn_header(sig.header, hir::Safety::Unsafe, attrs); + let header = + self.lower_fn_header(sig.header, sig.header_span(), hir::Safety::Unsafe, attrs); if define_opaque.is_some() { self.dcx().span_err(i.span, "foreign functions cannot define opaque types"); @@ -1742,7 +1741,7 @@ impl<'hir> LoweringContext<'_, 'hir> { coroutine_kind: Option, attrs: &[hir::Attribute], ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) { - let header = self.lower_fn_header(sig.header, hir::Safety::Safe, attrs); + let header = self.lower_fn_header(sig.header, sig.header_span(), hir::Safety::Safe, attrs); let itctx = ImplTraitContext::Universal; let (generics, decl) = self.lower_generics(generics, id, itctx, |this| { this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind) @@ -1753,6 +1752,7 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_fn_header( &mut self, h: FnHeader, + header_span: Span, default_safety: hir::Safety, attrs: &[hir::Attribute], ) -> hir::FnHeader { @@ -1780,13 +1780,12 @@ impl<'hir> LoweringContext<'_, 'hir> { 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 => {} + rustc_hir::Constness::Const { always: false } => {} + // A function can't just be `comptime`, it must also be `const`. + rustc_hir::Constness::NotConst => { + self.dcx().emit_err(NonConstComptimeFn { span: header_span, attr_span }); + } } } diff --git a/tests/ui/comptime/const_comptime.rs b/tests/ui/comptime/const_comptime.rs index 827e4dfcf545b..04d63985c92a1 100644 --- a/tests/ui/comptime/const_comptime.rs +++ b/tests/ui/comptime/const_comptime.rs @@ -1,7 +1,7 @@ #![feature(rustc_attrs)] #[rustc_comptime] -const fn foo() {} -//~^ ERROR a function cannot be both `comptime` and `const` +fn foo() {} +//~^ ERROR a function cannot just be `comptime` fn main() {} diff --git a/tests/ui/comptime/const_comptime.stderr b/tests/ui/comptime/const_comptime.stderr index 8be8ee7d69a1d..088989d367267 100644 --- a/tests/ui/comptime/const_comptime.stderr +++ b/tests/ui/comptime/const_comptime.stderr @@ -1,16 +1,16 @@ -error: a function cannot be both `comptime` and `const` +error: a function cannot just be `comptime` --> $DIR/const_comptime.rs:4:1 | LL | #[rustc_comptime] | ----------------- `comptime` because of this -LL | const fn foo() {} - | ^^^^^ help: remove the `const` +LL | fn foo() {} + | ^ help: add `const`: `const` | -note: `const` implies the function can be called at runtime, too +note: `const` is less restrictive than `comptime`, but already adds many restrictions `comptime` needs --> $DIR/const_comptime.rs:4:1 | -LL | const fn foo() {} - | ^^^^^ +LL | fn foo() {} + | ^ error: aborting due to 1 previous error diff --git a/tests/ui/comptime/feature-gate-test.rs b/tests/ui/comptime/feature-gate-test.rs index cd4ee521997e0..0c6fe00701100 100644 --- a/tests/ui/comptime/feature-gate-test.rs +++ b/tests/ui/comptime/feature-gate-test.rs @@ -1,5 +1,5 @@ #[rustc_comptime] //~^ ERROR use of an internal attribute -fn foo() {} +const fn foo() {} fn main() {} diff --git a/tests/ui/comptime/not_callable.rs b/tests/ui/comptime/not_callable.rs index c06e643d5403e..d4e72fa3fbfd2 100644 --- a/tests/ui/comptime/not_callable.rs +++ b/tests/ui/comptime/not_callable.rs @@ -1,7 +1,7 @@ #![feature(rustc_attrs, const_trait_impl)] #[rustc_comptime] -fn foo() {} +const fn foo() {} fn main() { // Ok @@ -16,7 +16,7 @@ const fn bar() { } #[rustc_comptime] -fn baz() { +const fn baz() { // Ok foo(); } diff --git a/tests/ui/comptime/trait_bounds.rs b/tests/ui/comptime/trait_bounds.rs index 3df2f41558fcc..a9b4b5a78d7a3 100644 --- a/tests/ui/comptime/trait_bounds.rs +++ b/tests/ui/comptime/trait_bounds.rs @@ -5,19 +5,18 @@ const trait Trait { } #[rustc_comptime] -fn always_const() { +const fn always_const() { T::method() } #[rustc_comptime] -fn conditionally_const() { - //~^ ERROR: `[const]` is not allowed here +const fn conditionally_const() { T::method() //~^ ERROR: `T: const Trait` is not satisfied } #[rustc_comptime] -fn non_const() { +const fn non_const() { T::method() //~^ ERROR: `T: const Trait` is not satisfied } diff --git a/tests/ui/comptime/trait_bounds.stderr b/tests/ui/comptime/trait_bounds.stderr index c5a03af2c0c2c..28c4330a704c2 100644 --- a/tests/ui/comptime/trait_bounds.stderr +++ b/tests/ui/comptime/trait_bounds.stderr @@ -1,27 +1,15 @@ -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 + --> $DIR/trait_bounds.rs:14:5 | LL | T::method() | ^ error[E0277]: the trait bound `T: const Trait` is not satisfied - --> $DIR/trait_bounds.rs:21:5 + --> $DIR/trait_bounds.rs:20:5 | LL | T::method() | ^ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/comptime/trait_comptime.rs b/tests/ui/comptime/trait_comptime.rs index a42e85c49f702..3e9d8fe2809e2 100644 --- a/tests/ui/comptime/trait_comptime.rs +++ b/tests/ui/comptime/trait_comptime.rs @@ -3,24 +3,27 @@ trait Foo { #[rustc_comptime] //~^ ERROR: cannot be used on required trait methods - fn foo(); + const fn foo(); + //~^ ERROR: functions in traits cannot be declared const #[rustc_comptime] //~^ ERROR: cannot be used on provided trait methods - fn bar() {} + const fn bar() {} + //~^ ERROR: functions in traits cannot be declared const } struct Bar; impl Bar { #[rustc_comptime] - fn foo() {} + const fn foo() {} } impl Foo for Bar { #[rustc_comptime] //~^ ERROR: cannot be used on trait methods - fn foo() {} + const fn foo() {} + //~^ ERROR: functions in trait impls cannot be declared const } fn main() {} diff --git a/tests/ui/comptime/trait_comptime.stderr b/tests/ui/comptime/trait_comptime.stderr index 06e982288471d..0e3e4c27ddb68 100644 --- a/tests/ui/comptime/trait_comptime.stderr +++ b/tests/ui/comptime/trait_comptime.stderr @@ -1,3 +1,30 @@ +error[E0379]: functions in traits cannot be declared const + --> $DIR/trait_comptime.rs:6:5 + | +LL | const fn foo(); + | ^^^^^- + | | + | functions in traits cannot be const + | help: remove the `const` + +error[E0379]: functions in traits cannot be declared const + --> $DIR/trait_comptime.rs:11:5 + | +LL | const fn bar() {} + | ^^^^^- + | | + | functions in traits cannot be const + | help: remove the `const` + +error[E0379]: functions in trait impls cannot be declared const + --> $DIR/trait_comptime.rs:25:5 + | +LL | const fn foo() {} + | ^^^^^- + | | + | functions in trait impls cannot be const + | help: remove the `const` + error: `#[rustc_comptime]` attribute cannot be used on required trait methods --> $DIR/trait_comptime.rs:4:5 | @@ -7,7 +34,7 @@ LL | #[rustc_comptime] = help: `#[rustc_comptime]` can only be applied to functions with a body error: `#[rustc_comptime]` attribute cannot be used on provided trait methods - --> $DIR/trait_comptime.rs:8:5 + --> $DIR/trait_comptime.rs:9:5 | LL | #[rustc_comptime] | ^^^^^^^^^^^^^^^^^ @@ -15,12 +42,13 @@ 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 + --> $DIR/trait_comptime.rs:23:5 | LL | #[rustc_comptime] | ^^^^^^^^^^^^^^^^^ | = help: `#[rustc_comptime]` can be applied to functions and inherent methods -error: aborting due to 3 previous errors +error: aborting due to 6 previous errors +For more information about this error, try `rustc --explain E0379`.