rustc_middle/ty/
rvalue_scopes.rs

1use rustc_hir as hir;
2use rustc_hir::ItemLocalMap;
3use rustc_macros::{HashStable, TyDecodable, TyEncodable};
4use tracing::debug;
5
6use crate::middle::region::{Scope, ScopeData, ScopeTree};
7
8/// `RvalueScopes` is a mapping from sub-expressions to _extended_ lifetime as determined by
9/// rules laid out in `rustc_hir_analysis::check::rvalue_scopes`.
10#[derive(TyEncodable, TyDecodable, Clone, Debug, Default, Eq, PartialEq, HashStable)]
11pub struct RvalueScopes {
12    map: ItemLocalMap<Option<Scope>>,
13}
14
15impl RvalueScopes {
16    pub fn new() -> Self {
17        Self { map: <_>::default() }
18    }
19
20    /// Returns the scope when the temp created by `expr_id` will be cleaned up.
21    /// It also emits a lint on potential backwards incompatible change to the temporary scope
22    /// which is *for now* always shortening.
23    pub fn temporary_scope(
24        &self,
25        region_scope_tree: &ScopeTree,
26        expr_id: hir::ItemLocalId,
27    ) -> (Option<Scope>, Option<Scope>) {
28        // Check for a designated rvalue scope.
29        if let Some(&s) = self.map.get(&expr_id) {
30            debug!("temporary_scope({expr_id:?}) = {s:?} [custom]");
31            return (s, None);
32        }
33
34        // Otherwise, locate the innermost terminating scope
35        // if there's one. Static items, for instance, won't
36        // have an enclosing scope, hence no scope will be
37        // returned.
38        region_scope_tree
39            .default_temporary_scope(Scope { local_id: expr_id, data: ScopeData::Node })
40    }
41
42    /// Make an association between a sub-expression and an extended lifetime
43    pub fn record_rvalue_scope(&mut self, var: hir::ItemLocalId, lifetime: Option<Scope>) {
44        debug!("record_rvalue_scope(var={var:?}, lifetime={lifetime:?})");
45        if let Some(lifetime) = lifetime {
46            assert!(var != lifetime.local_id);
47        }
48        self.map.insert(var, lifetime);
49    }
50}