mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-26 13:01:27 +03:00
Rollup merge of #154957 - lapla-cogito:issue_153891, r=oli-obk
Fix ICE when const closure appears inside a non-const trait method Fixes rust-lang/rust#153891 `hir_body_const_context()` unconditionally delegated to the parent's const context for const closures, returning `None` when the parent had no const context. This caused `mir_const_qualif()` to hit a `span_bug!`, since `mir_promoted()` had already decided to call it based on the closure's own syntactic constness. Fall back to `ConstContext::ConstFn` when the parent's const context is `None`, so that the const closure body is still properly const-checked rather than triggering an ICE. Examining [another attempt](https://github.com/rust-lang/rust/pull/153900/changes) at this issue (which has already been closed), I thought that its approach represents a workaround fix to avoid inconsistencies in the caller of `mir_promoted()`, whereas I think the correct behavior is for `hir_body_const_context()` itself to return the proper value.
This commit is contained in:
@@ -319,7 +319,17 @@ pub fn hir_body_const_context(self, local_def_id: LocalDefId) -> Option<ConstCon
|
||||
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 self.hir_body_const_context(self.local_parent(local_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
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
BodyOwnerKind::Fn if self.is_const_fn(def_id) => ConstContext::ConstFn,
|
||||
BodyOwnerKind::Fn | BodyOwnerKind::Closure | BodyOwnerKind::GlobalAsm => return None,
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(const_closures)]
|
||||
|
||||
// Regression test for https://github.com/rust-lang/rust/issues/153891
|
||||
|
||||
const trait Foo {
|
||||
fn test() -> impl [const] Fn();
|
||||
}
|
||||
|
||||
impl<T: Foo> Foo for &mut T {
|
||||
const fn test() -> impl [const] Fn() {
|
||||
//~^ ERROR functions in trait impls cannot be declared const
|
||||
const move || {}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,19 @@
|
||||
error[E0379]: functions in trait impls cannot be declared const
|
||||
--> $DIR/const-closure-in-non-const-trait-impl-method.rs:11:5
|
||||
|
|
||||
LL | const fn test() -> impl [const] Fn() {
|
||||
| ^^^^^ functions in trait impls cannot be const
|
||||
|
|
||||
help: remove the `const` ...
|
||||
|
|
||||
LL - const fn test() -> impl [const] Fn() {
|
||||
LL + fn test() -> impl [const] Fn() {
|
||||
|
|
||||
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
|
||||
|
||||
For more information about this error, try `rustc --explain E0379`.
|
||||
@@ -0,0 +1,12 @@
|
||||
#![feature(const_closures)]
|
||||
|
||||
// Regression test for https://github.com/rust-lang/rust/issues/153891
|
||||
|
||||
trait Tr {
|
||||
const fn test() {
|
||||
//~^ ERROR functions in traits cannot be declared const
|
||||
(const || {})()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,12 @@
|
||||
error[E0379]: functions in traits cannot be declared const
|
||||
--> $DIR/const-closure-in-non-const-trait-method.rs:6:5
|
||||
|
|
||||
LL | const fn test() {
|
||||
| ^^^^^-
|
||||
| |
|
||||
| functions in traits cannot be const
|
||||
| help: remove the `const`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0379`.
|
||||
Reference in New Issue
Block a user