1
Fork 0

Rollup merge of #134797 - spastorino:ergonomic-ref-counting-1, r=nikomatsakis

Ergonomic ref counting

This is an experimental first version of ergonomic ref counting.

This first version implements most of the RFC but doesn't implement any of the optimizations. This was left for following iterations.

RFC: https://github.com/rust-lang/rfcs/pull/3680
Tracking issue: https://github.com/rust-lang/rust/issues/132290
Project goal: https://github.com/rust-lang/rust-project-goals/issues/107

r? ```@nikomatsakis```
This commit is contained in:
Matthias Krüger 2025-03-07 19:15:33 +01:00 committed by GitHub
commit f5a143f796
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
119 changed files with 1401 additions and 79 deletions

View file

@ -582,6 +582,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::Yield { .. }
| ExprKind::ThreadLocalRef(_)
| ExprKind::Call { .. }
| ExprKind::ByUse { .. }
| ExprKind::WrapUnsafeBinder { .. } => {
// these are not places, so we need to make a temporary.
debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Place)));

View file

@ -572,6 +572,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
block.and(Rvalue::Use(operand))
}
ExprKind::ByUse { expr, span: _ } => {
let operand = unpack!(
block =
this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::No)
);
block.and(Rvalue::Use(operand))
}
}
}

View file

@ -56,6 +56,7 @@ impl Category {
| ExprKind::RawBorrow { .. }
| ExprKind::Yield { .. }
| ExprKind::Call { .. }
| ExprKind::ByUse { .. }
| ExprKind::InlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::Into)),
ExprKind::Array { .. }

View file

@ -4,11 +4,14 @@ use rustc_ast::{AsmMacro, InlineAsmOptions};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_middle::mir::*;
use rustc_middle::span_bug;
use rustc_middle::thir::*;
use rustc_middle::ty::CanonicalUserTypeAnnotation;
use rustc_middle::ty::{CanonicalUserTypeAnnotation, Ty};
use rustc_span::DUMMY_SP;
use rustc_span::source_map::Spanned;
use rustc_trait_selection::infer::InferCtxtExt;
use tracing::{debug, instrument};
use crate::builder::expr::category::{Category, RvalueFunc};
@ -289,6 +292,57 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
this.diverge_from(block);
success.unit()
}
ExprKind::ByUse { expr, span } => {
let place = unpack!(block = this.as_place(block, expr));
let ty = place.ty(&this.local_decls, this.tcx).ty;
if this.tcx.type_is_copy_modulo_regions(this.infcx.typing_env(this.param_env), ty) {
this.cfg.push_assign(
block,
source_info,
destination,
Rvalue::Use(Operand::Copy(place)),
);
block.unit()
} else if this.infcx.type_is_use_cloned_modulo_regions(this.param_env, ty) {
// Convert `expr.use` to a call like `Clone::clone(&expr)`
let success = this.cfg.start_new_block();
let clone_trait = this.tcx.require_lang_item(LangItem::Clone, None);
let clone_fn = this.tcx.associated_item_def_ids(clone_trait)[0];
let func = Operand::function_handle(this.tcx, clone_fn, [ty.into()], expr_span);
let ref_ty = Ty::new_imm_ref(this.tcx, this.tcx.lifetimes.re_erased, ty);
let ref_place = this.temp(ref_ty, span);
this.cfg.push_assign(
block,
source_info,
ref_place,
Rvalue::Ref(this.tcx.lifetimes.re_erased, BorrowKind::Shared, place),
);
this.cfg.terminate(
block,
source_info,
TerminatorKind::Call {
func,
args: [Spanned { node: Operand::Move(ref_place), span: DUMMY_SP }]
.into(),
destination,
target: Some(success),
unwind: UnwindAction::Unreachable,
call_source: CallSource::Misc,
fn_span: expr_span,
},
);
success.unit()
} else {
this.cfg.push_assign(
block,
source_info,
destination,
Rvalue::Use(Operand::Move(place)),
);
block.unit()
}
}
ExprKind::Use { source } => this.expr_into_dest(destination, block, source),
ExprKind::Borrow { arg, borrow_kind } => {
// We don't do this in `as_rvalue` because we use `as_place`

View file

@ -37,7 +37,7 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
.map(|captured_place| {
let name = captured_place.to_symbol();
match captured_place.info.capture_kind {
ty::UpvarCapture::ByValue => name,
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => name,
ty::UpvarCapture::ByRef(..) => Symbol::intern(&format!("_ref__{name}")),
}
})
@ -871,7 +871,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let mut projs = closure_env_projs.clone();
projs.push(ProjectionElem::Field(FieldIdx::new(i), ty));
match capture {
ty::UpvarCapture::ByValue => {}
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {}
ty::UpvarCapture::ByRef(..) => {
projs.push(ProjectionElem::Deref);
}

View file

@ -451,6 +451,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
| ExprKind::Tuple { .. }
| ExprKind::Unary { .. }
| ExprKind::Call { .. }
| ExprKind::ByUse { .. }
| ExprKind::Assign { .. }
| ExprKind::AssignOp { .. }
| ExprKind::Break { .. }

View file

@ -464,6 +464,10 @@ impl<'tcx> ThirBuildCx<'tcx> {
}
}
hir::ExprKind::Use(expr, span) => {
ExprKind::ByUse { expr: self.mirror_expr(expr), span }
}
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, arg) => {
ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg: self.mirror_expr(arg) }
}
@ -648,7 +652,7 @@ impl<'tcx> ThirBuildCx<'tcx> {
}
},
hir::ExprKind::Closure { .. } => {
hir::ExprKind::Closure(hir::Closure { .. }) => {
let closure_ty = self.typeck_results.expr_ty(expr);
let (def_id, args, movability) = match *closure_ty.kind() {
ty::Closure(def_id, args) => (def_id, UpvarArgs::Closure(args), None),
@ -1248,6 +1252,17 @@ impl<'tcx> ThirBuildCx<'tcx> {
match upvar_capture {
ty::UpvarCapture::ByValue => captured_place_expr,
ty::UpvarCapture::ByUse => {
let span = captured_place_expr.span;
let expr_id = self.thir.exprs.push(captured_place_expr);
Expr {
temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
ty: upvar_ty,
span: closure_expr.span,
kind: ExprKind::ByUse { expr: expr_id, span },
}
}
ty::UpvarCapture::ByRef(upvar_borrow) => {
let borrow_kind = match upvar_borrow {
ty::BorrowKind::Immutable => BorrowKind::Shared,

View file

@ -345,6 +345,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
| Borrow { .. }
| Box { .. }
| Call { .. }
| ByUse { .. }
| Closure { .. }
| ConstBlock { .. }
| ConstParam { .. }

View file

@ -246,6 +246,13 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
print_indented!(self, "}", depth_lvl);
}
ByUse { expr, span } => {
print_indented!(self, "ByUse {", depth_lvl);
print_indented!(self, "expr:", depth_lvl + 1);
self.print_expr(*expr, depth_lvl + 2);
print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
print_indented!(self, "}", depth_lvl);
}
Deref { arg } => {
print_indented!(self, "Deref {", depth_lvl);
self.print_expr(*arg, depth_lvl + 1);