use super::FnCtxt; use hir::def_id::DefId; use hir::Node; use rustc_hir as hir; use rustc_middle::middle::region::{RvalueCandidateType, Scope, ScopeTree}; use rustc_middle::ty::RvalueScopes; /// Applied to an expression `expr` if `expr` -- or something owned or partially owned by /// `expr` -- is going to be indirectly referenced by a variable in a let statement. In that /// case, the "temporary lifetime" or `expr` is extended to be the block enclosing the `let` /// statement. /// /// More formally, if `expr` matches the grammar `ET`, record the rvalue scope of the matching /// `` as `blk_id`: /// /// ```text /// ET = *ET /// | ET[...] /// | ET.f /// | (ET) /// | /// ``` /// /// Note: ET is intended to match "rvalues or places based on rvalues". fn record_rvalue_scope_rec( rvalue_scopes: &mut RvalueScopes, mut expr: &hir::Expr<'_>, lifetime: Option, ) { loop { // Note: give all the expressions matching `ET` with the // extended temporary lifetime, not just the innermost rvalue, // because in codegen if we must compile e.g., `*rvalue()` // into a temporary, we request the temporary scope of the // outer expression. rvalue_scopes.record_rvalue_scope(expr.hir_id.local_id, lifetime); match expr.kind { hir::ExprKind::AddrOf(_, _, subexpr) | hir::ExprKind::Unary(hir::UnOp::Deref, subexpr) | hir::ExprKind::Field(subexpr, _) | hir::ExprKind::Index(subexpr, _) => { expr = subexpr; } _ => { return; } } } } fn record_rvalue_scope( rvalue_scopes: &mut RvalueScopes, expr: &hir::Expr<'_>, candidate: &RvalueCandidateType, ) { debug!("resolve_rvalue_scope(expr={expr:?}, candidate={candidate:?})"); match candidate { RvalueCandidateType::Borrow { lifetime, .. } | RvalueCandidateType::Pattern { lifetime, .. } => { record_rvalue_scope_rec(rvalue_scopes, expr, *lifetime) } // FIXME(@dingxiangfei2009): handle the candidates in the function call arguments } } pub fn resolve_rvalue_scopes<'a, 'tcx>( fcx: &'a FnCtxt<'a, 'tcx>, scope_tree: &'a ScopeTree, def_id: DefId, ) -> RvalueScopes { let tcx = &fcx.tcx; let hir_map = tcx.hir(); let mut rvalue_scopes = RvalueScopes::new(); debug!("start resolving rvalue scopes, def_id={def_id:?}"); debug!("rvalue_scope: rvalue_candidates={:?}", scope_tree.rvalue_candidates); for (&hir_id, candidate) in &scope_tree.rvalue_candidates { let Some(Node::Expr(expr)) = hir_map.find(hir_id) else { bug!("hir node does not exist") }; record_rvalue_scope(&mut rvalue_scopes, expr, candidate); } rvalue_scopes }