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