Compare commits

...

8 Commits

Author SHA1 Message Date
bors
2f43fe4303 Auto merge of #155863 - jhpratt:rollup-6wWyVPM, r=jhpratt
Some checks failed
CI / Calculate job matrix (push) Has been cancelled
CI / ${{ matrix.full_name }} (push) Has been cancelled
CI / publish toolstate (push) Has been cancelled
Rollup of 3 pull requests

Successful merges:

 - rust-lang/rust#155772 (Check closure's constness validity in the constness query)
 - rust-lang/rust#155833 (CI: rfl: move job forward to Linux v7.0)
 - rust-lang/rust#155839 (Remove unnecessary requires_lto: false for eBPF)
2026-04-27 07:49:26 +00:00
Jacob Pratt
88cc0052ec Rollup merge of #155839 - bjorn3:remove_unnecessary_target_override, r=jieyouxu
Remove unnecessary requires_lto: false for eBPF

requires_lto is already false by default.
2026-04-27 03:48:44 -04:00
Jacob Pratt
d03a7c9bf6 Rollup merge of #155833 - ojeda:rfl, r=lqd
CI: rfl: move job forward to Linux v7.0

This version contains both of the workarounds we had, thus remove them as well.

r? @lqd @Kobzol
try-job: x86_64-rust-for-linux
@rustbot label A-rust-for-linux
@bors try
2026-04-27 03:48:44 -04:00
Jacob Pratt
6897624a46 Rollup merge of #155772 - oli-obk:const-closures-everywhere, r=fee1-dead
Check closure's constness validity in the constness query

fixes rust-lang/rust#155584

instead of checking during ast lowering, where it's not easily possible to obtain all the right information in time. While lowering an assoc item we don't know if the parent was a const trait or a const impl. Tracing this information is quite annoying, and complicates a lot of code, which checking here after the fact is trivial.
2026-04-27 03:48:43 -04:00
Oli Scherer
8e1c34f5cc Check closure's constness validity in the constness query
instead of during ast lowering, where it's not easily possible to obtain all the right information in time
2026-04-27 07:44:19 +02:00
Oli Scherer
2b2f28d0ea Add regression test 2026-04-27 07:43:46 +02:00
bjorn3
effe8b5235 Remove unnecessary requires_lto: false for eBPF
requires_lto is already false by default.
2026-04-26 21:07:25 +02:00
Miguel Ojeda
1e6ba4f385 CI: rfl: move job forward to Linux v7.0
This version contains both of the workarounds we had, thus remove them
as well.

Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2026-04-26 17:49:24 +02:00
13 changed files with 57 additions and 50 deletions

View File

@@ -1052,7 +1052,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
binder: &ClosureBinder,
capture_clause: CaptureBy,
closure_id: NodeId,
mut constness: Const,
constness: Const,
movability: Movability,
decl: &FnDecl,
body: &Expr,
@@ -1062,18 +1062,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
let closure_def_id = self.local_def_id(closure_id);
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
if let Const::Yes(span) = constness {
if !self.is_in_const_context {
self.dcx().span_err(span, "cannot use `const` closures outside of const contexts");
constness = Const::No;
}
}
let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| {
let mut coroutine_kind = find_attr!(attrs, Coroutine(_) => hir::CoroutineKind::Coroutine(Movability::Movable));
// FIXME(contracts): Support contracts on closures?
let body_id = this.lower_fn_body(decl, None, constness, |this| {
let body_id = this.lower_fn_body(decl, None, |this| {
this.coroutine_kind = coroutine_kind;
let e = this.lower_expr_mut(body);
coroutine_kind = this.coroutine_kind;

View File

@@ -1,5 +1,3 @@
use std::mem;
use rustc_abi::ExternAbi;
use rustc_ast::visit::AssocCtxt;
use rustc_ast::*;
@@ -378,7 +376,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
body.as_deref(),
attrs,
contract.as_deref(),
header.constness,
);
let itctx = ImplTraitContext::Universal;
@@ -1068,7 +1065,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
Some(body),
attrs,
contract.as_deref(),
sig.header.constness,
);
let (generics, sig) = self.lower_method_sig(
generics,
@@ -1262,7 +1258,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
body.as_deref(),
attrs,
contract.as_deref(),
sig.header.constness,
);
let (generics, sig) = self.lower_method_sig(
generics,
@@ -1391,13 +1386,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
f: impl FnOnce(&mut Self) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>),
) -> hir::BodyId {
let prev_coroutine_kind = self.coroutine_kind.take();
let prev_is_in_const_context = mem::take(&mut self.is_in_const_context);
let task_context = self.task_context.take();
let (parameters, result) = f(self);
let body_id = self.record_body(parameters, result);
self.task_context = task_context;
self.coroutine_kind = prev_coroutine_kind;
self.is_in_const_context = prev_is_in_const_context;
body_id
}
@@ -1416,13 +1409,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
&mut self,
decl: &FnDecl,
contract: Option<&FnContract>,
constness: Const,
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
) -> hir::BodyId {
self.lower_body(|this| {
if let Const::Yes(_) = constness {
this.is_in_const_context = true;
}
let params =
this.arena.alloc_from_iter(decl.inputs.iter().map(|x| this.lower_param(x)));
@@ -1440,9 +1429,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
decl: &FnDecl,
body: &Block,
contract: Option<&FnContract>,
constness: Const,
) -> hir::BodyId {
self.lower_fn_body(decl, contract, constness, |this| this.lower_block_expr(body))
self.lower_fn_body(decl, contract, |this| this.lower_block_expr(body))
}
pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId {
@@ -1450,10 +1438,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
(
&[],
match expr {
Some(expr) => {
this.is_in_const_context = true;
this.lower_expr_mut(expr)
}
Some(expr) => this.lower_expr_mut(expr),
None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")),
},
)
@@ -1472,13 +1457,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
body: Option<&Block>,
attrs: &'hir [hir::Attribute],
contract: Option<&FnContract>,
constness: Const,
) -> hir::BodyId {
let Some(body) = body else {
// Functions without a body are an error, except if this is an intrinsic. For those we
// create a fake body so that the entire rest of the compiler doesn't have to deal with
// this as a special case.
return self.lower_fn_body(decl, contract, constness, |this| {
return self.lower_fn_body(decl, contract, |this| {
if find_attr!(attrs, RustcIntrinsic) || this.tcx.is_sdylib_interface_build() {
let span = this.lower_span(span);
let empty_block = hir::Block {
@@ -1503,7 +1487,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
};
let Some(coroutine_kind) = coroutine_kind else {
// Typical case: not a coroutine.
return self.lower_fn_body_block(decl, body, contract, constness);
return self.lower_fn_body_block(decl, body, contract);
};
// FIXME(contracts): Support contracts on async fn.
self.lower_body(|this| {

View File

@@ -124,7 +124,6 @@ struct LoweringContext<'a, 'hir> {
loop_scope: Option<HirId>,
is_in_loop_condition: bool,
is_in_dyn_type: bool,
is_in_const_context: bool,
current_hir_id_owner: hir::OwnerId,
item_local_id_counter: hir::ItemLocalId,
@@ -193,7 +192,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
loop_scope: None,
is_in_loop_condition: false,
is_in_dyn_type: false,
is_in_const_context: false,
coroutine_kind: None,
task_context: None,
current_item: None,

View File

@@ -16,7 +16,13 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Constness {
// Foreign functions cannot be evaluated at compile-time.
Constness::NotConst
}
Node::Expr(e) if let ExprKind::Closure(c) = e.kind => c.constness,
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() {
tcx.dcx().span_err(tcx.def_span(def_id), "cannot use `const` closures outside of const contexts");
return Constness::NotConst;
}
c.constness
},
// FIXME(fee1-dead): extract this one out and rename this query to `fn_constness` so we don't need `is_const_fn` anymore.
Node::Item(i) if let ItemKind::Impl(impl_) = i.kind => impl_.constness,
Node::Item(Item { kind: ItemKind::Fn { sig, .. }, .. }) => sig.header.constness,

View File

@@ -319,17 +319,7 @@ impl<'tcx> TyCtxt<'tcx> {
BodyOwnerKind::Fn if self.is_constructor(def_id) => return None,
// Const closures use their parent's const context
BodyOwnerKind::Closure if self.is_const_fn(def_id) => {
return Some(
self.hir_body_const_context(self.local_parent(local_def_id)).unwrap_or_else(
|| {
assert!(
self.dcx().has_errors().is_some(),
"`const` closure with no enclosing const context",
);
ConstContext::ConstFn
},
),
);
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 | BodyOwnerKind::Closure | BodyOwnerKind::GlobalAsm => return None,

View File

@@ -18,7 +18,6 @@ pub(crate) fn opts(endian: Endian) -> TargetOptions {
// BPF_PROG_LOAD and not all BPF libraries do that yet
merge_functions: MergeFunctions::Disabled,
obj_is_bitcode: true,
requires_lto: false,
singlethread: true,
// When targeting the `v3` cpu in llvm, 32-bit atomics are also supported.
// But making this value change based on the target cpu can be mostly confusing

View File

@@ -2,9 +2,7 @@
set -euo pipefail
# https://github.com/rust-lang/rust/pull/151534
# https://github.com/rust-lang/rust/pull/149389
LINUX_VERSION=167ea5357eb7c3a39200627a36dfbfe249576192
LINUX_VERSION=v7.0
# Build rustc, rustdoc, cargo, clippy-driver and rustfmt
../x.py build --stage 2 library rustdoc clippy rustfmt

View File

@@ -0,0 +1,25 @@
//@ check-pass
#![feature(const_closures, const_destruct, const_trait_impl)]
use std::marker::Destruct;
use std::num::NonZero;
const trait T {
fn a(&mut self, f: impl [const] Fn() + [const] Destruct);
fn b(&mut self);
}
struct S;
impl const T for S {
fn a(&mut self, f: impl [const] Fn() + [const] Destruct) {
f()
}
fn b(&mut self) {
self.a(const || {});
}
}
fn main() {}

View File

@@ -11,6 +11,7 @@ impl<T: Foo> Foo for &mut T {
const fn test() -> impl [const] Fn() {
//~^ ERROR functions in trait impls cannot be declared const
const move || {}
//~^ ERROR: cannot use `const` closures outside of const contexts
}
}

View File

@@ -14,6 +14,12 @@ help: ... and declare the impl to be const instead
LL | impl<T: Foo> const Foo for &mut T {
| +++++
error: aborting due to 1 previous error
error: cannot use `const` closures outside of const contexts
--> $DIR/const-closure-in-non-const-trait-impl-method.rs:13:9
|
LL | const move || {}
| ^^^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0379`.

View File

@@ -6,6 +6,7 @@ trait Tr {
const fn test() {
//~^ ERROR functions in traits cannot be declared const
(const || {})()
//~^ ERROR cannot use `const` closures outside of const contexts
}
}

View File

@@ -7,6 +7,12 @@ LL | const fn test() {
| functions in traits cannot be const
| help: remove the `const`
error: aborting due to 1 previous error
error: cannot use `const` closures outside of const contexts
--> $DIR/const-closure-in-non-const-trait-method.rs:8:10
|
LL | (const || {})()
| ^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0379`.

View File

@@ -2,7 +2,7 @@ error: cannot use `const` closures outside of const contexts
--> $DIR/non-const-op-const-closure-non-const-outer.rs:14:6
|
LL | (const || { (()).foo() })();
| ^^^^^
| ^^^^^^^^
error: aborting due to 1 previous error