Skip to content

Commit 0e50d5a

Browse files
committed
merge RvalueScopes into ScopeTree
This removes some unneeded indirection and consolidates the logic for scope resolution.
1 parent 9606412 commit 0e50d5a

File tree

12 files changed

+99
-207
lines changed

12 files changed

+99
-207
lines changed

compiler/rustc_hir_analysis/src/check/region.rs

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -516,12 +516,10 @@ fn resolve_local<'tcx>(
516516

517517
if let Some(pat) = pat {
518518
if is_binding_pat(pat) {
519-
visitor.scope_tree.record_rvalue_candidate(
520-
expr.hir_id,
521-
RvalueCandidate {
522-
target: expr.hir_id.local_id,
523-
lifetime: visitor.cx.var_parent,
524-
},
519+
record_subexpr_extended_temp_scopes(
520+
&mut visitor.scope_tree,
521+
expr,
522+
visitor.cx.var_parent,
525523
);
526524
}
527525
}
@@ -604,7 +602,7 @@ fn resolve_local<'tcx>(
604602
}
605603
}
606604

607-
/// If `expr` matches the `E&` grammar, then records an extended rvalue scope as appropriate:
605+
/// If `expr` matches the `E&` grammar, then records an extended temporary scope as appropriate:
608606
///
609607
/// ```text
610608
/// E& = & ET
@@ -627,10 +625,7 @@ fn resolve_local<'tcx>(
627625
match expr.kind {
628626
hir::ExprKind::AddrOf(_, _, subexpr) => {
629627
record_rvalue_scope_if_borrow_expr(visitor, subexpr, blk_id);
630-
visitor.scope_tree.record_rvalue_candidate(
631-
subexpr.hir_id,
632-
RvalueCandidate { target: subexpr.hir_id.local_id, lifetime: blk_id },
633-
);
628+
record_subexpr_extended_temp_scopes(&mut visitor.scope_tree, subexpr, blk_id);
634629
}
635630
hir::ExprKind::Struct(_, fields, _) => {
636631
for field in fields {
@@ -687,6 +682,53 @@ fn resolve_local<'tcx>(
687682
}
688683
}
689684

685+
/// Applied to an expression `expr` if `expr` -- or something owned or partially owned by
686+
/// `expr` -- is going to be indirectly referenced by a variable in a let statement. In that
687+
/// case, the "temporary lifetime" of `expr` is extended to be the block enclosing the `let`
688+
/// statement.
689+
///
690+
/// More formally, if `expr` matches the grammar `ET`, record the temporary scope of the matching
691+
/// `<rvalue>` as `lifetime`:
692+
///
693+
/// ```text
694+
/// ET = *ET
695+
/// | ET[...]
696+
/// | ET.f
697+
/// | (ET)
698+
/// | <rvalue>
699+
/// ```
700+
///
701+
/// Note: ET is intended to match "rvalues or places based on rvalues".
702+
fn record_subexpr_extended_temp_scopes(
703+
scope_tree: &mut ScopeTree,
704+
mut expr: &hir::Expr<'_>,
705+
lifetime: Option<Scope>,
706+
) {
707+
debug!(?expr, ?lifetime);
708+
709+
loop {
710+
// Note: give all the expressions matching `ET` with the
711+
// extended temporary lifetime, not just the innermost rvalue,
712+
// because in MIR building if we must compile e.g., `*rvalue()`
713+
// into a temporary, we request the temporary scope of the
714+
// outer expression.
715+
716+
scope_tree.record_extended_temp_scope(expr.hir_id.local_id, lifetime);
717+
718+
match expr.kind {
719+
hir::ExprKind::AddrOf(_, _, subexpr)
720+
| hir::ExprKind::Unary(hir::UnOp::Deref, subexpr)
721+
| hir::ExprKind::Field(subexpr, _)
722+
| hir::ExprKind::Index(subexpr, _, _) => {
723+
expr = subexpr;
724+
}
725+
_ => {
726+
return;
727+
}
728+
}
729+
}
730+
}
731+
690732
impl<'tcx> ScopeResolutionVisitor<'tcx> {
691733
/// Records the current parent (if any) as the parent of `child_scope`.
692734
fn record_child_scope(&mut self, child_scope: Scope) {

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use tracing::{debug, instrument};
4040
use crate::callee::{self, DeferredCallResolution};
4141
use crate::errors::{self, CtorIsPrivate};
4242
use crate::method::{self, MethodCallee};
43-
use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy, rvalue_scopes};
43+
use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy};
4444

4545
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
4646
/// Produces warning on the given node, if the current point in the
@@ -604,13 +604,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
604604
self.normalize(span, field.ty(self.tcx, args))
605605
}
606606

607-
pub(crate) fn resolve_rvalue_scopes(&self, def_id: DefId) {
608-
let scope_tree = self.tcx.region_scope_tree(def_id);
609-
let rvalue_scopes = { rvalue_scopes::resolve_rvalue_scopes(self, scope_tree, def_id) };
610-
let mut typeck_results = self.typeck_results.borrow_mut();
611-
typeck_results.rvalue_scopes = rvalue_scopes;
612-
}
613-
614607
/// Drain all obligations that are stalled on coroutines defined in this body.
615608
#[instrument(level = "debug", skip(self))]
616609
pub(crate) fn drain_stalled_coroutine_obligations(&self) {

compiler/rustc_hir_typeck/src/lib.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ mod op;
3737
mod opaque_types;
3838
mod pat;
3939
mod place_op;
40-
mod rvalue_scopes;
4140
mod typeck_root_ctxt;
4241
mod upvar;
4342
mod writeback;
@@ -237,9 +236,6 @@ fn typeck_with_inspect<'tcx>(
237236
// because they don't constrain other type variables.
238237
fcx.closure_analyze(body);
239238
assert!(fcx.deferred_call_resolutions.borrow().is_empty());
240-
// Before the coroutine analysis, temporary scopes shall be marked to provide more
241-
// precise information on types to be captured.
242-
fcx.resolve_rvalue_scopes(def_id.to_def_id());
243239

244240
for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
245241
let ty = fcx.normalize(span, ty);

compiler/rustc_hir_typeck/src/rvalue_scopes.rs

Lines changed: 0 additions & 79 deletions
This file was deleted.

compiler/rustc_hir_typeck/src/writeback.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7979
wbcx.visit_offset_of_container_types();
8080
wbcx.visit_potentially_region_dependent_goals();
8181

82-
wbcx.typeck_results.rvalue_scopes =
83-
mem::take(&mut self.typeck_results.borrow_mut().rvalue_scopes);
84-
8582
let used_trait_imports =
8683
mem::take(&mut self.typeck_results.borrow_mut().used_trait_imports);
8784
debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);

compiler/rustc_middle/src/middle/region.rs

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use std::fmt;
1111
use rustc_data_structures::fx::FxIndexMap;
1212
use rustc_data_structures::unord::UnordMap;
1313
use rustc_hir as hir;
14-
use rustc_hir::{HirId, HirIdMap, Node};
14+
use rustc_hir::{HirId, ItemLocalMap, Node};
1515
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
1616
use rustc_span::{DUMMY_SP, Span};
1717
use tracing::debug;
@@ -221,29 +221,19 @@ pub struct ScopeTree {
221221
/// variable is declared.
222222
var_map: FxIndexMap<hir::ItemLocalId, Scope>,
223223

224-
/// Identifies expressions which, if captured into a temporary, ought to
225-
/// have a temporary whose lifetime extends to the end of the enclosing *block*,
226-
/// and not the enclosing *statement*. Expressions that are not present in this
227-
/// table are not rvalue candidates. The set of rvalue candidates is computed
228-
/// during type check based on a traversal of the AST.
229-
pub rvalue_candidates: HirIdMap<RvalueCandidate>,
224+
/// Tracks expressions with extended temporary scopes, based on the syntactic rules for
225+
/// temporary lifetime extension. Further details may be found in
226+
/// `rustc_hir_analysis::check::region` and in the [Reference].
227+
///
228+
/// [Reference]: https://doc.rust-lang.org/nightly/reference/destructors.html#temporary-lifetime-extension
229+
extended_temp_scopes: ItemLocalMap<Option<Scope>>,
230230

231231
/// Backwards incompatible scoping that will be introduced in future editions.
232232
/// This information is used later for linting to identify locals and
233233
/// temporary values that will receive backwards-incompatible drop orders.
234234
pub backwards_incompatible_scope: UnordMap<hir::ItemLocalId, Scope>,
235235
}
236236

237-
/// See the `rvalue_candidates` field for more information on rvalue
238-
/// candidates in general.
239-
/// The `lifetime` field is None to indicate that certain expressions escape
240-
/// into 'static and should have no local cleanup scope.
241-
#[derive(Debug, Copy, Clone, HashStable)]
242-
pub struct RvalueCandidate {
243-
pub target: hir::ItemLocalId,
244-
pub lifetime: Option<Scope>,
245-
}
246-
247237
impl ScopeTree {
248238
pub fn record_scope_parent(&mut self, child: Scope, parent: Option<Scope>) {
249239
debug!("{:?}.parent = {:?}", child, parent);
@@ -260,12 +250,13 @@ impl ScopeTree {
260250
self.var_map.insert(var, lifetime);
261251
}
262252

263-
pub fn record_rvalue_candidate(&mut self, var: HirId, candidate: RvalueCandidate) {
264-
debug!("record_rvalue_candidate(var={var:?}, candidate={candidate:?})");
265-
if let Some(lifetime) = &candidate.lifetime {
266-
assert!(var.local_id != lifetime.local_id)
253+
/// Make an association between a sub-expression and an extended lifetime
254+
pub fn record_extended_temp_scope(&mut self, var: hir::ItemLocalId, lifetime: Option<Scope>) {
255+
debug!(?var, ?lifetime);
256+
if let Some(lifetime) = lifetime {
257+
assert!(var != lifetime.local_id);
267258
}
268-
self.rvalue_candidates.insert(var, candidate);
259+
self.extended_temp_scopes.insert(var, lifetime);
269260
}
270261

271262
/// Returns the narrowest scope that encloses `id`, if any.
@@ -337,4 +328,20 @@ impl ScopeTree {
337328

338329
span_bug!(ty::tls::with(|tcx| inner.span(tcx, self)), "no enclosing temporary scope")
339330
}
331+
332+
/// Returns the scope when the temp created by `expr_id` will be cleaned up.
333+
/// It also emits a lint on potential backwards incompatible change to the temporary scope
334+
/// which is *for now* always shortening.
335+
pub fn temporary_scope(&self, expr_id: hir::ItemLocalId) -> (Option<Scope>, Option<Scope>) {
336+
// Check for a designated extended temporary scope.
337+
if let Some(&s) = self.extended_temp_scopes.get(&expr_id) {
338+
debug!("temporary_scope({expr_id:?}) = {s:?} [custom]");
339+
return (s, None);
340+
}
341+
342+
// Otherwise, locate the innermost terminating scope.
343+
let (scope, backward_incompatible) =
344+
self.default_temporary_scope(Scope { local_id: expr_id, data: ScopeData::Node });
345+
(Some(scope), backward_incompatible)
346+
}
340347
}

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ pub use self::region::{
9797
BoundRegion, BoundRegionKind, EarlyParamRegion, LateParamRegion, LateParamRegionKind, Region,
9898
RegionKind, RegionVid,
9999
};
100-
pub use self::rvalue_scopes::RvalueScopes;
101100
pub use self::sty::{
102101
AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig,
103102
CoroutineArgsExt, EarlyBinder, FnSig, InlineConstArgs, InlineConstArgsParts, ParamConst,
@@ -156,7 +155,6 @@ mod list;
156155
mod opaque_types;
157156
mod predicate;
158157
mod region;
159-
mod rvalue_scopes;
160158
mod structural_impls;
161159
#[allow(hidden_glob_reexports)]
162160
mod sty;

compiler/rustc_middle/src/ty/rvalue_scopes.rs

Lines changed: 0 additions & 48 deletions
This file was deleted.

0 commit comments

Comments
 (0)