Rollup merge of #154595 - mu001999-contrib:fix/154539, r=BoxyUwU

Emit fatal on invalid const args with nested defs

Fixed https://github.com/rust-lang/rust/issues/123629
Fixes https://github.com/rust-lang/rust/issues/154539

Invalid const args are rejected, so their surrounding HIR is not preserved. But nested defs inside them can still get created, leaving children lowered without a valid HIR parent and causing an ICE when later error handling walks HIR parents.

r? @BoxyUwU
This commit is contained in:
Jacob Pratt
2026-04-16 01:54:05 -04:00
committed by GitHub
19 changed files with 234 additions and 155 deletions
+13 -13
View File
@@ -29,7 +29,7 @@
use crate::errors::{InvalidLegacyConstGenericArg, UseConstGenericArg, YieldInClosure};
use crate::{AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, TryBlockScope};
struct WillCreateDefIdsVisitor {}
pub(super) struct WillCreateDefIdsVisitor;
impl<'v> rustc_ast::visit::Visitor<'v> for WillCreateDefIdsVisitor {
type Result = ControlFlow<Span>;
@@ -479,18 +479,18 @@ fn lower_legacy_const_generics(
DefPathData::LateAnonConst,
f.span,
);
let mut visitor = WillCreateDefIdsVisitor {};
let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) {
Box::new(Expr {
id: self.next_node_id(),
kind: ExprKind::Err(invalid_expr_error(self.tcx, span)),
span: f.span,
attrs: [].into(),
tokens: None,
})
} else {
arg
};
let const_value =
if let ControlFlow::Break(span) = WillCreateDefIdsVisitor.visit_expr(&arg) {
Box::new(Expr {
id: self.next_node_id(),
kind: ExprKind::Err(invalid_expr_error(self.tcx, span)),
span: f.span,
attrs: [].into(),
tokens: None,
})
} else {
arg
};
let anon_const = AnonConst {
id: node_id,
+25 -11
View File
@@ -39,6 +39,7 @@
use std::sync::Arc;
use rustc_ast::node_id::NodeMap;
use rustc_ast::visit::Visitor;
use rustc_ast::{self as ast, *};
use rustc_attr_parsing::{AttributeParser, Late, OmitDoc};
use rustc_data_structures::fingerprint::Fingerprint;
@@ -2219,14 +2220,22 @@ fn lower_generic_param_kind(
// since later compiler stages cannot handle them (and shouldn't need to be able to).
let default = default
.as_ref()
.filter(|_| match source {
.filter(|anon_const| match source {
hir::GenericParamSource::Generics => true,
hir::GenericParamSource::Binder => {
self.dcx().emit_err(errors::GenericParamDefaultInBinder {
span: param.span(),
});
false
let err = errors::GenericParamDefaultInBinder { span: param.span() };
if expr::WillCreateDefIdsVisitor
.visit_expr(&anon_const.value)
.is_break()
{
// FIXME(mgca): make this non-fatal once we have a better way
// to handle nested items in anno const from binder
// Issue: https://github.com/rust-lang/rust/issues/123629
self.dcx().emit_fatal(err)
} else {
self.dcx().emit_err(err);
false
}
}
})
.map(|def| self.lower_anon_const_to_const_arg_and_alloc(def));
@@ -2563,12 +2572,17 @@ fn lower_expr_to_const_arg_direct(&mut self, expr: &Expr) -> hir::ConstArg<'hir>
let span = self.lower_span(expr.span);
let overly_complex_const = |this: &mut Self| {
let e = this.dcx().struct_span_err(
expr.span,
"complex const arguments must be placed inside of a `const` block",
);
let msg = "complex const arguments must be placed inside of a `const` block";
let e = if expr::WillCreateDefIdsVisitor.visit_expr(expr).is_break() {
// FIXME(mgca): make this non-fatal once we have a better way to handle
// nested items in const args
// Issue: https://github.com/rust-lang/rust/issues/154539
this.dcx().struct_span_fatal(expr.span, msg).emit()
} else {
this.dcx().struct_span_err(expr.span, msg).emit()
};
ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(e.emit()), span }
ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(e), span }
};
match &expr.kind {
-10
View File
@@ -1,10 +0,0 @@
//@ known-bug: #123629
#![feature(generic_assert)]
fn foo()
where
for<const N: usize = { assert!(u) }> ():,
{
}
fn main() {}
@@ -0,0 +1,12 @@
#![feature(generic_assert)]
fn foo()
where
for<const N: usize = { assert!(u) }> ():,
//~^ ERROR cannot find value `u` in this scope
//~^^ ERROR only lifetime parameters can be used in this context
//~^^^ ERROR defaults for generic parameters are not allowed in `for<...>` binders
{
}
fn main() {}
@@ -0,0 +1,26 @@
error[E0425]: cannot find value `u` in this scope
--> $DIR/bad-defaults-for-generic-param-in-binder-123629.rs:5:36
|
LL | for<const N: usize = { assert!(u) }> ():,
| ^ not found in this scope
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/bad-defaults-for-generic-param-in-binder-123629.rs:5:15
|
LL | for<const N: usize = { assert!(u) }> ():,
| ^
|
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: defaults for generic parameters are not allowed in `for<...>` binders
--> $DIR/bad-defaults-for-generic-param-in-binder-123629.rs:5:9
|
LL | for<const N: usize = { assert!(u) }> ():,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0425, E0658.
For more information about an error, try `rustc --explain E0425`.
@@ -0,0 +1,8 @@
error: complex const arguments must be placed inside of a `const` block
--> $DIR/array-expr-complex.rs:11:28
|
LL | takes_array::<{ [1, 2, 1 + 2] }>();
| ^^^^^
error: aborting due to 1 previous error
@@ -0,0 +1,8 @@
error: complex const arguments must be placed inside of a `const` block
--> $DIR/array-expr-complex.rs:14:21
|
LL | takes_array::<{ [X; 3] }>();
| ^^^^^^
error: aborting due to 1 previous error
@@ -0,0 +1,8 @@
error: complex const arguments must be placed inside of a `const` block
--> $DIR/array-expr-complex.rs:17:21
|
LL | takes_array::<{ [0; Y] }>();
| ^^^^^^
error: aborting due to 1 previous error
@@ -1,3 +1,5 @@
//@ revisions: r1 r2 r3
#![expect(incomplete_features)]
#![feature(min_generic_const_args, adt_const_params)]
@@ -5,12 +7,15 @@
fn generic_caller<const X: u32, const Y: usize>() {
// not supported yet
#[cfg(r1)]
takes_array::<{ [1, 2, 1 + 2] }>();
//~^ ERROR: complex const arguments must be placed inside of a `const` block
//[r1]~^ ERROR: complex const arguments must be placed inside of a `const` block
#[cfg(r2)]
takes_array::<{ [X; 3] }>();
//~^ ERROR: complex const arguments must be placed inside of a `const` block
//[r2]~^ ERROR: complex const arguments must be placed inside of a `const` block
#[cfg(r3)]
takes_array::<{ [0; Y] }>();
//~^ ERROR: complex const arguments must be placed inside of a `const` block
//[r3]~^ ERROR: complex const arguments must be placed inside of a `const` block
}
fn main() {}
@@ -1,20 +0,0 @@
error: complex const arguments must be placed inside of a `const` block
--> $DIR/array-expr-complex.rs:8:28
|
LL | takes_array::<{ [1, 2, 1 + 2] }>();
| ^^^^^
error: complex const arguments must be placed inside of a `const` block
--> $DIR/array-expr-complex.rs:10:21
|
LL | takes_array::<{ [X; 3] }>();
| ^^^^^^
error: complex const arguments must be placed inside of a `const` block
--> $DIR/array-expr-complex.rs:12:21
|
LL | takes_array::<{ [0; Y] }>();
| ^^^^^^
error: aborting due to 3 previous errors
@@ -0,0 +1,12 @@
#![feature(min_generic_const_args)]
trait Iter<
const FN: fn() = {
|| { //~ ERROR complex const arguments must be placed inside of a `const` block
use std::io::*;
write!(_, "")
}
},
>
{
}
@@ -0,0 +1,11 @@
error: complex const arguments must be placed inside of a `const` block
--> $DIR/bad-const-arg-fn-154539.rs:5:9
|
LL | / || {
LL | | use std::io::*;
LL | | write!(_, "")
LL | | }
| |_________^
error: aborting due to 1 previous error
@@ -0,0 +1,23 @@
error[E0428]: the name `foo` is defined multiple times
--> $DIR/hir-crate-items-before-lowering-ices.rs:13:17
|
LL | fn foo() {}
| -------- previous definition of the value `foo` here
LL | reuse foo;
| ^^^^^^^^^^ `foo` redefined here
|
= note: `foo` must be defined only once in the value namespace of this block
error: complex const arguments must be placed inside of a `const` block
--> $DIR/hir-crate-items-before-lowering-ices.rs:11:13
|
LL | / {
LL | | fn foo() {}
LL | | reuse foo;
LL | | 2
LL | | },
| |_____________^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0428`.
@@ -0,0 +1,12 @@
error: `#[deprecated]` attribute cannot be used on delegations
--> $DIR/hir-crate-items-before-lowering-ices.rs:27:9
|
LL | #[deprecated]
| ^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= help: `#[deprecated]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, foreign statics, functions, inherent impl blocks, macro defs, modules, statics, struct fields, traits, type aliases, and use statements
= note: `#[deny(useless_deprecated)]` on by default
error: aborting due to 1 previous error
@@ -0,0 +1,24 @@
error[E0061]: this function takes 0 arguments but 1 argument was supplied
--> $DIR/hir-crate-items-before-lowering-ices.rs:37:11
|
LL | reuse a as b {
| ___________^______-
LL | | fn foo<T>() {};
LL | | foo
LL | | }
| |_____- unexpected argument of type `fn() {foo::<_>}`
|
note: function defined here
--> $DIR/hir-crate-items-before-lowering-ices.rs:35:8
|
LL | fn a() {}
| ^
help: remove the extra argument
|
LL - reuse a as b {
LL + reuse {
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0061`.
@@ -0,0 +1,13 @@
error: complex const arguments must be placed inside of a `const` block
--> $DIR/hir-crate-items-before-lowering-ices.rs:47:13
|
LL | / {
LL | |
LL | | struct W<I>;
LL | | impl<I> W<I> {
... |
LL | | },
| |_____________^
error: aborting due to 1 previous error
@@ -0,0 +1,16 @@
error[E0425]: cannot find value `async` in this scope
--> $DIR/hir-crate-items-before-lowering-ices.rs:66:13
|
LL | async || {};
| ^^^^^ not found in this scope
error[E0308]: mismatched types
--> $DIR/hir-crate-items-before-lowering-ices.rs:66:22
|
LL | async || {};
| ^^ expected `bool`, found `()`
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0308, E0425.
For more information about an error, try `rustc --explain E0308`.
@@ -1,13 +1,16 @@
//@ revisions: ice_155125 ice_155127 ice_155128 ice_155164 ice_155202
#![feature(min_generic_const_args, fn_delegation)]
#![allow(incomplete_features)]
#[cfg(ice_155125)]
mod ice_155125 {
struct S<const N: usize>;
impl
S<
{ //~ ERROR: complex const arguments must be placed inside of a `const` block
{ //[ice_155125]~ ERROR: complex const arguments must be placed inside of a `const` block
fn foo() {}
reuse foo; //~ ERROR: the name `foo` is defined multiple times
reuse foo; //[ice_155125]~ ERROR: the name `foo` is defined multiple times
2
},
>
@@ -15,32 +18,34 @@ fn foo() {}
}
}
#[cfg(ice_155127)]
mod ice_155127 {
struct S;
fn foo() {}
impl S {
#[deprecated] //~ ERROR: `#[deprecated]` attribute cannot be used on delegations
//~^ WARN: this was previously accepted by the compiler but is being phased out;
#[deprecated] //[ice_155127]~ ERROR: `#[deprecated]` attribute cannot be used on delegations
//[ice_155127]~^ WARN: this was previously accepted by the compiler but is being phased out;
reuse foo;
}
}
#[cfg(ice_155128)]
mod ice_155128 {
fn a() {}
reuse a as b { //~ ERROR: this function takes 0 arguments but 1 argument was supplied
reuse a as b { //[ice_155128]~ ERROR: this function takes 0 arguments but 1 argument was supplied
fn foo<T>() {};
foo
}
}
#[cfg(ice_155164)]
mod ice_155164 {
struct X<const N: usize, F> {
inner: std::iter::Map<
{
//~^ ERROR: complex const arguments must be placed inside of a `const` block
//~| ERROR: constant provided when a type was expected
//[ice_155164]~^ ERROR: complex const arguments must be placed inside of a `const` block
struct W<I>;
impl<I> W<I> {
reuse Iterator::fold;
@@ -51,14 +56,15 @@ impl<I> W<I> {
}
}
#[cfg(ice_155202)]
mod ice_155202 {
trait Trait {
fn bar(self);
}
impl Trait for () {
reuse Trait::bar {
async || {}; //~ ERROR: mismatched types
//~^ ERROR: cannot find value `async` in this scope
async || {}; //[ice_155202]~ ERROR: mismatched types
//[ice_155202]~^ ERROR: cannot find value `async` in this scope
}
}
}
@@ -1,89 +0,0 @@
error[E0428]: the name `foo` is defined multiple times
--> $DIR/hir-crate-items-before-lowering-ices.rs:10:17
|
LL | fn foo() {}
| -------- previous definition of the value `foo` here
LL | reuse foo;
| ^^^^^^^^^^ `foo` redefined here
|
= note: `foo` must be defined only once in the value namespace of this block
error[E0425]: cannot find value `async` in this scope
--> $DIR/hir-crate-items-before-lowering-ices.rs:60:13
|
LL | async || {};
| ^^^^^ not found in this scope
error: complex const arguments must be placed inside of a `const` block
--> $DIR/hir-crate-items-before-lowering-ices.rs:8:13
|
LL | / {
LL | | fn foo() {}
LL | | reuse foo;
LL | | 2
LL | | },
| |_____________^
error: complex const arguments must be placed inside of a `const` block
--> $DIR/hir-crate-items-before-lowering-ices.rs:41:13
|
LL | / {
LL | |
LL | |
LL | | struct W<I>;
... |
LL | | },
| |_____________^
error: `#[deprecated]` attribute cannot be used on delegations
--> $DIR/hir-crate-items-before-lowering-ices.rs:23:9
|
LL | #[deprecated]
| ^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= help: `#[deprecated]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, foreign statics, functions, inherent impl blocks, macro defs, modules, statics, struct fields, traits, type aliases, and use statements
= note: `#[deny(useless_deprecated)]` on by default
error[E0747]: constant provided when a type was expected
--> $DIR/hir-crate-items-before-lowering-ices.rs:41:13
|
LL | / {
LL | |
LL | |
LL | | struct W<I>;
... |
LL | | },
| |_____________^
error[E0061]: this function takes 0 arguments but 1 argument was supplied
--> $DIR/hir-crate-items-before-lowering-ices.rs:32:11
|
LL | reuse a as b {
| ___________^______-
LL | | fn foo<T>() {};
LL | | foo
LL | | }
| |_____- unexpected argument of type `fn() {b::foo::<_>}`
|
note: function defined here
--> $DIR/hir-crate-items-before-lowering-ices.rs:30:8
|
LL | fn a() {}
| ^
help: remove the extra argument
|
LL - reuse a as b {
LL + reuse {
|
error[E0308]: mismatched types
--> $DIR/hir-crate-items-before-lowering-ices.rs:60:22
|
LL | async || {};
| ^^ expected `bool`, found `()`
error: aborting due to 8 previous errors
Some errors have detailed explanations: E0061, E0308, E0425, E0428, E0747.
For more information about an error, try `rustc --explain E0061`.