rust-lang/rust · critical
no sub-expr expected for {parent_node:?}
Error message
no sub-expr expected for {parent_node:?} What it means
unreachable! in the same function expr_guaranteed_to_constitute_read_for_never (compiler/rustc_middle/src/hir/mod.rs:353), but on the parent-node branch. After handling Node::Expr parents, the match falls through to a list of Node variants that cannot legally be the parent of a place-expression child (Param, Item, TraitItem, ImplItem, Variant, Field, PathSegment, Ty, Lifetime, Crate, Infer, WherePredicate, OpaqueTy, etc.). Hitting it means an Expr was found as a direct child of one of those non-expression-bearing nodes.
Source
Thrown at compiler/rustc_middle/src/hir/mod.rs:353
| Node::PathSegment(_)
| Node::Ty(_)
| Node::AssocItemConstraint(_)
| Node::TraitRef(_)
| Node::PatField(_)
| Node::PatExpr(_)
| Node::LetStmt(_)
| Node::Synthetic
| Node::Err(_)
| Node::Ctor(_)
| Node::Lifetime(_)
| Node::GenericParam(_)
| Node::Crate(_)
| Node::Infer(_)
| Node::WherePredicate(_)
| Node::PreciseCapturingNonLifetimeArg(_)
| Node::ConstArgExprField(_)
| Node::OpaqueTy(_) => {
unreachable!("no sub-expr expected for {parent_node:?}")
}
}
}
#[inline]
fn hir_owner_parent_impl(self, owner_id: OwnerId) -> HirId {
self.opt_local_parent(owner_id.def_id).map_or(CRATE_HIR_ID, |parent_def_id| {
let parent_owner_id = self.local_def_id_to_hir_id(parent_def_id).owner;
HirId {
owner: parent_owner_id,
local_id: self
.hir_owner(parent_owner_id.def_id)
.unwrap()
.parenting
.get(&owner_id.def_id)
.copied()
.unwrap_or(ItemLocalId::ZERO),
}View on GitHub (pinned to 22057b88b0)
Solutions
- Report as a rustc ICE including the parent_node printed in the message and (if possible) the offending span.
- Bisect nightlies to locate the HIR-parenting regression.
- If authoring proc-macros, ensure emitted Exprs are placed where the HIR visitor expects them (blocks, statement lists, expression positions), not under type/item nodes.
Defensive patterns
Strategy: type-guard
Validate before calling
// Same class as 237 but for a parent_node. Verify the parent
// expression kind before expecting a child sub-expression.
use rustc_hir::{Expr, ExprKind};
fn parent_node_has_sub_expr(parent: &Expr<'_>) -> bool {
!matches!(
parent.kind,
ExprKind::Lit(_)
| ExprKind::Path(_)
| ExprKind::ConstBlock(_)
| ExprKind::Field(_, _)
)
} Type guard
// Type-guard that narrows a parent Expr to a composite kind
// before descending into its sub-expression slot.
use rustc_hir::{Expr, ExprKind};
enum SubExprSlot<'a> {
Lhs(&'a Expr<'a>),
Rhs(&'a Expr<'a>),
Callee(&'a Expr<'a>),
Scrutinee(&'a Expr<'a>),
}
fn parent_sub_expr_slot<'a>(parent: &'a Expr<'a>) -> Option<SubExprSlot<'a>> {
match parent.kind {
ExprKind::Binary(_, lhs, rhs) => Some(SubExprSlot::Lhs(lhs)),
ExprKind::Assign(lhs, rhs, _) => Some(SubExprSlot::Rhs(rhs)),
ExprKind::Call(callee, _) => Some(SubExprSlot::Callee(callee)),
ExprKind::Match(scrut, _, _) => Some(SubExprSlot::Scrutinee(scrut)),
_ => None,
}
} Prevention
- Match on parent_node.kind and only descend when a sub-expression slot provably exists
- Treat leaf ExprKinds (Lit, Path, ConstBlock) as terminal in your HIR walker
- Add unit tests covering every ExprKind variant for any visitor that calls sub-expr accessors
- Avoid relying on parent_node context from macro-generated code, which can carry unexpected shapes
When it happens
Trigger: parent_hir_node(expr.hir_id) returns one of the listed non-expression Node variants while expr is a syntactic place expression. Indicates malformed HIR parenting, e.g. an Expr wrongly parented under an Item or a Ty rather than under a Block/Expr/Stmt.
Common situations: Proc-macros or compiler bugs that mis-wire HirId parents; desugaring regressions where the parent pointer is not updated; analysis tools that traverse HIR assuming every Expr is parented under an Expr/Block.
Related errors
- no sub-expr expected for {:?}
- already handled
- not a module: {node:?}
- processing delegation
- Not a HIR owner
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/beadf76429b1870d.json.
Report an issue: GitHub.