rustc_hir_typeck/
rvalue_scopes.rs

1use hir::Node;
2use hir::def_id::DefId;
3use rustc_hir as hir;
4use rustc_middle::bug;
5use rustc_middle::middle::region::{
6    ScopeCompatibility, RvalueCandidate, Scope, ScopeTree,
7};
8use rustc_middle::ty::RvalueScopes;
9use tracing::debug;
10
11use super::FnCtxt;
12
13/// Applied to an expression `expr` if `expr` -- or something owned or partially owned by
14/// `expr` -- is going to be indirectly referenced by a variable in a let statement. In that
15/// case, the "temporary lifetime" or `expr` is extended to be the block enclosing the `let`
16/// statement.
17///
18/// More formally, if `expr` matches the grammar `ET`, record the rvalue scope of the matching
19/// `<rvalue>` as `blk_id`:
20///
21/// ```text
22///     ET = *ET
23///        | ET[...]
24///        | ET.f
25///        | (ET)
26///        | <rvalue>
27/// ```
28///
29/// Note: ET is intended to match "rvalues or places based on rvalues".
30fn record_rvalue_scope_rec(
31    rvalue_scopes: &mut RvalueScopes,
32    mut expr: &hir::Expr<'_>,
33    lifetime: Option<Scope>,
34    compat: ScopeCompatibility,
35) {
36    loop {
37        // Note: give all the expressions matching `ET` with the
38        // extended temporary lifetime, not just the innermost rvalue,
39        // because in codegen if we must compile e.g., `*rvalue()`
40        // into a temporary, we request the temporary scope of the
41        // outer expression.
42
43        rvalue_scopes.record_rvalue_scope(expr.hir_id.local_id, lifetime, compat);
44
45        match expr.kind {
46            hir::ExprKind::AddrOf(_, _, subexpr)
47            | hir::ExprKind::Unary(hir::UnOp::Deref, subexpr)
48            | hir::ExprKind::Field(subexpr, _)
49            | hir::ExprKind::Index(subexpr, _, _) => {
50                expr = subexpr;
51            }
52            _ => {
53                return;
54            }
55        }
56    }
57}
58fn record_rvalue_scope(
59    rvalue_scopes: &mut RvalueScopes,
60    expr: &hir::Expr<'_>,
61    candidate: &RvalueCandidate,
62) {
63    debug!("resolve_rvalue_scope(expr={expr:?}, candidate={candidate:?})");
64    record_rvalue_scope_rec(rvalue_scopes, expr, candidate.lifetime, candidate.compat)
65    // FIXME(@dingxiangfei2009): handle the candidates in the function call arguments
66}
67
68pub(crate) fn resolve_rvalue_scopes<'a, 'tcx>(
69    fcx: &'a FnCtxt<'a, 'tcx>,
70    scope_tree: &'a ScopeTree,
71    def_id: DefId,
72) -> RvalueScopes {
73    let tcx = &fcx.tcx;
74    let mut rvalue_scopes = RvalueScopes::new();
75    debug!("start resolving rvalue scopes, def_id={def_id:?}");
76    debug!("rvalue_scope: rvalue_candidates={:?}", scope_tree.rvalue_candidates);
77    for (&hir_id, candidate) in &scope_tree.rvalue_candidates {
78        let Node::Expr(expr) = tcx.hir_node(hir_id) else { bug!("hir node does not exist") };
79        record_rvalue_scope(&mut rvalue_scopes, expr, candidate);
80    }
81    rvalue_scopes
82}