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

  1. Report as a rustc ICE including the parent_node printed in the message and (if possible) the offending span.
  2. Bisect nightlies to locate the HIR-parenting regression.
  3. 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

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


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/beadf76429b1870d.json. Report an issue: GitHub.