Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions compiler/rustc_ast_lowering/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
37 changes: 18 additions & 19 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<Output = T>` here because lower_body
Expand All @@ -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);
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -1742,7 +1741,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
coroutine_kind: Option<CoroutineKind>,
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)
Expand All @@ -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 {
Expand Down Expand Up @@ -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 });
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions tests/ui/comptime/const_comptime.rs
Original file line number Diff line number Diff line change
@@ -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() {}
12 changes: 6 additions & 6 deletions tests/ui/comptime/const_comptime.stderr
Original file line number Diff line number Diff line change
@@ -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

2 changes: 1 addition & 1 deletion tests/ui/comptime/feature-gate-test.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#[rustc_comptime]
//~^ ERROR use of an internal attribute
fn foo() {}
const fn foo() {}

fn main() {}
4 changes: 2 additions & 2 deletions tests/ui/comptime/not_callable.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![feature(rustc_attrs, const_trait_impl)]

#[rustc_comptime]
fn foo() {}
const fn foo() {}

fn main() {
// Ok
Expand All @@ -16,7 +16,7 @@ const fn bar() {
}

#[rustc_comptime]
fn baz() {
const fn baz() {
// Ok
foo();
}
7 changes: 3 additions & 4 deletions tests/ui/comptime/trait_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,18 @@ const trait Trait {
}

#[rustc_comptime]
fn always_const<T: const Trait>() {
const fn always_const<T: const Trait>() {
T::method()
}

#[rustc_comptime]
fn conditionally_const<T: [const] Trait>() {
//~^ ERROR: `[const]` is not allowed here
const fn conditionally_const<T: [const] Trait>() {

@fee1-dead fee1-dead Jun 9, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need this error though.. because comptime isn't conditionally const

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea that's not possible, this check happens on ast xD now that you remind me of this, that probably was another reason I did it this way

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that's a bummer.

Well, it's an unstable feature, so I guess we'll just have to live with this oddity for now.

As a matter of style it'd be good to typically put the attribute directly above the function, to minimize the risk of it being missed.

T::method()
//~^ ERROR: `T: const Trait` is not satisfied
}

#[rustc_comptime]
fn non_const<T: Trait>() {
const fn non_const<T: Trait>() {
T::method()
//~^ ERROR: `T: const Trait` is not satisfied
}
Expand Down
18 changes: 3 additions & 15 deletions tests/ui/comptime/trait_bounds.stderr
Original file line number Diff line number Diff line change
@@ -1,27 +1,15 @@
error: `[const]` is not allowed here
--> $DIR/trait_bounds.rs:13:27
|
LL | fn conditionally_const<T: [const] Trait>() {
| ^^^^^^^
|
note: this function is not `const`, so it cannot have `[const]` trait bounds
--> $DIR/trait_bounds.rs:13:4
|
LL | fn conditionally_const<T: [const] Trait>() {
| ^^^^^^^^^^^^^^^^^^^

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`.
11 changes: 7 additions & 4 deletions tests/ui/comptime/trait_comptime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
34 changes: 31 additions & 3 deletions tests/ui/comptime/trait_comptime.stderr
Original file line number Diff line number Diff line change
@@ -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
|
Expand All @@ -7,20 +34,21 @@ 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]
| ^^^^^^^^^^^^^^^^^
|
= 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`.
Loading