Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 1c34390

Browse files
committedJun 4, 2024
Auto merge of rust-lang#125923 - matthewjasper:no-return-leak, r=<try>
Fix leaks from panics in destructors Resurrects rust-lang#78373. This avoids the problem with rust-lang#80949 by not unscheduling drops of function arguments until after the call (so they still get a drop terminator on the function unwind path). Closes rust-lang#47949 r? `@lcnr`
2 parents 85f90a4 + 28ac9be commit 1c34390

21 files changed

+711
-486
lines changed
 

‎compiler/rustc_mir_build/src/build/block.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1111
pub(crate) fn ast_block(
1212
&mut self,
1313
destination: Place<'tcx>,
14+
scope: Option<Scope>,
1415
block: BasicBlock,
1516
ast_block: BlockId,
1617
source_info: SourceInfo,
@@ -19,18 +20,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1920
self.thir[ast_block];
2021
self.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
2122
if targeted_by_break {
22-
this.in_breakable_scope(None, destination, span, |this| {
23-
Some(this.ast_block_stmts(destination, block, span, stmts, expr, region_scope))
23+
this.in_breakable_scope(None, destination, scope, span, |this| {
24+
Some(this.ast_block_stmts(
25+
destination,
26+
scope,
27+
block,
28+
span,
29+
stmts,
30+
expr,
31+
region_scope,
32+
))
2433
})
2534
} else {
26-
this.ast_block_stmts(destination, block, span, stmts, expr, region_scope)
35+
this.ast_block_stmts(destination, scope, block, span, stmts, expr, region_scope)
2736
}
2837
})
2938
}
3039

3140
fn ast_block_stmts(
3241
&mut self,
3342
destination: Place<'tcx>,
43+
scope: Option<Scope>,
3444
mut block: BasicBlock,
3545
span: Span,
3646
stmts: &[StmtId],
@@ -168,6 +178,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
168178
unpack!(
169179
failure_block = this.ast_block(
170180
dummy_place,
181+
None,
171182
failure_entry,
172183
*else_block,
173184
this.source_info(else_block_span),
@@ -321,7 +332,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
321332
this.block_context
322333
.push(BlockFrame::TailExpr { tail_result_is_ignored, span: expr.span });
323334

324-
unpack!(block = this.expr_into_dest(destination, block, expr_id));
335+
unpack!(block = this.expr_into_dest(destination, scope, block, expr_id));
325336
let popped = this.block_context.pop();
326337

327338
assert!(popped.is_some_and(|bf| bf.is_tail_expr()));

‎compiler/rustc_mir_build/src/build/expr/as_rvalue.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ use rustc_middle::ty::{self, Ty, UpvarArgs};
2020
use rustc_span::{Span, DUMMY_SP};
2121
use tracing::debug;
2222

23+
use std::slice;
24+
2325
impl<'a, 'tcx> Builder<'a, 'tcx> {
2426
/// Returns an rvalue suitable for use until the end of the current
2527
/// scope expression.
@@ -183,15 +185,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
183185
let box_ = Rvalue::ShallowInitBox(Operand::Move(storage), value_ty);
184186
this.cfg.push_assign(block, source_info, Place::from(result), box_);
185187

186-
// initialize the box contents:
188+
// Initialize the box contents. No scope is needed since the
189+
// `Box` is already scheduled to be dropped.
187190
unpack!(
188191
block = this.expr_into_dest(
189192
this.tcx.mk_place_deref(Place::from(result)),
193+
None,
190194
block,
191195
value,
192196
)
193197
);
194-
block.and(Rvalue::Use(Operand::Move(Place::from(result))))
198+
let result_operand = Operand::Move(Place::from(result));
199+
this.record_operands_moved(slice::from_ref(&result_operand));
200+
block.and(Rvalue::Use(result_operand))
195201
}
196202
ExprKind::Cast { source } => {
197203
let source_expr = &this.thir[source];
@@ -359,6 +365,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
359365
})
360366
.collect();
361367

368+
this.record_operands_moved(&fields.raw);
362369
block.and(Rvalue::Aggregate(Box::new(AggregateKind::Array(el_ty)), fields))
363370
}
364371
ExprKind::Tuple { ref fields } => {
@@ -380,6 +387,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
380387
})
381388
.collect();
382389

390+
this.record_operands_moved(&fields.raw);
383391
block.and(Rvalue::Aggregate(Box::new(AggregateKind::Tuple), fields))
384392
}
385393
ExprKind::Closure(box ClosureExpr {
@@ -482,6 +490,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
482490
Box::new(AggregateKind::CoroutineClosure(closure_id.to_def_id(), args))
483491
}
484492
};
493+
this.record_operands_moved(&operands.raw);
485494
block.and(Rvalue::Aggregate(result, operands))
486495
}
487496
ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
@@ -737,7 +746,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
737746
this.diverge_from(block);
738747
block = success;
739748
}
740-
this.record_operands_moved(&[Spanned { node: value_operand, span: DUMMY_SP }]);
749+
this.record_operands_moved(&[value_operand]);
741750
}
742751
block.and(Rvalue::Aggregate(Box::new(AggregateKind::Array(elem_ty)), IndexVec::new()))
743752
}

‎compiler/rustc_mir_build/src/build/expr/as_temp.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
112112
}
113113
}
114114

115-
unpack!(block = this.expr_into_dest(temp_place, block, expr_id));
116-
117-
if let Some(temp_lifetime) = temp_lifetime {
118-
this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value);
119-
}
115+
unpack!(block = this.expr_into_dest(temp_place, temp_lifetime, block, expr_id));
120116

121117
block.and(temp)
122118
}

‎compiler/rustc_mir_build/src/build/expr/into.rs

Lines changed: 84 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
//! See docs in build/expr/mod.rs
22
33
use crate::build::expr::category::{Category, RvalueFunc};
4+
use crate::build::scope::DropKind;
45
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, NeedsTemporary};
56
use rustc_ast::InlineAsmOptions;
67
use rustc_data_structures::fx::FxHashMap;
78
use rustc_data_structures::stack::ensure_sufficient_stack;
89
use rustc_hir as hir;
10+
use rustc_index::IndexVec;
11+
use rustc_middle::middle::region;
912
use rustc_middle::mir::*;
1013
use rustc_middle::span_bug;
1114
use rustc_middle::thir::*;
@@ -14,13 +17,16 @@ use rustc_span::source_map::Spanned;
1417
use std::iter;
1518
use tracing::{debug, instrument};
1619

20+
use std::slice;
21+
1722
impl<'a, 'tcx> Builder<'a, 'tcx> {
1823
/// Compile `expr`, storing the result into `destination`, which
1924
/// is assumed to be uninitialized.
2025
#[instrument(level = "debug", skip(self))]
2126
pub(crate) fn expr_into_dest(
2227
&mut self,
2328
destination: Place<'tcx>,
29+
scope: Option<region::Scope>,
2430
mut block: BasicBlock,
2531
expr_id: ExprId,
2632
) -> BlockAnd<()> {
@@ -35,6 +41,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3541
let expr_is_block_or_scope =
3642
matches!(expr.kind, ExprKind::Block { .. } | ExprKind::Scope { .. });
3743

44+
let schedule_drop = move |this: &mut Self| {
45+
if let Some(drop_scope) = scope {
46+
let local =
47+
destination.as_local().expect("cannot schedule drop of non-Local place");
48+
this.schedule_drop(expr_span, drop_scope, local, DropKind::Value);
49+
}
50+
};
51+
3852
if !expr_is_block_or_scope {
3953
this.block_context.push(BlockFrame::SubExpr);
4054
}
@@ -44,15 +58,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4458
let region_scope = (region_scope, source_info);
4559
ensure_sufficient_stack(|| {
4660
this.in_scope(region_scope, lint_level, |this| {
47-
this.expr_into_dest(destination, block, value)
61+
this.expr_into_dest(destination, scope, block, value)
4862
})
4963
})
5064
}
5165
ExprKind::Block { block: ast_block } => {
52-
this.ast_block(destination, block, ast_block, source_info)
66+
this.ast_block(destination, scope, block, ast_block, source_info)
5367
}
5468
ExprKind::Match { scrutinee, ref arms, .. } => this.match_expr(
5569
destination,
70+
scope,
5671
block,
5772
scrutinee,
5873
arms,
@@ -90,7 +105,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
90105
));
91106

92107
// Lower the `then` arm into its block.
93-
this.expr_into_dest(destination, then_blk, then)
108+
let then_blk =
109+
this.expr_into_dest(destination, scope, then_blk, then);
110+
if let Some(drop_scope) = scope {
111+
let local = destination
112+
.as_local()
113+
.expect("cannot unschedule drop of non-Local place");
114+
this.unschedule_drop(drop_scope, local);
115+
}
116+
then_blk
94117
});
95118

96119
// Pack `(then_block, else_block)` into `BlockAnd<BasicBlock>`.
@@ -104,7 +127,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
104127

105128
// If there is an `else` arm, lower it into `else_blk`.
106129
if let Some(else_expr) = else_opt {
107-
unpack!(else_blk = this.expr_into_dest(destination, else_blk, else_expr));
130+
unpack!(
131+
else_blk = this.expr_into_dest(destination, scope, else_blk, else_expr)
132+
);
108133
} else {
109134
// There is no `else` arm, so we know both arms have type `()`.
110135
// Generate the implicit `else {}` by assigning unit.
@@ -139,6 +164,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
139164

140165
// This is an optimization. If the expression was a call then we already have an
141166
// unreachable block. Don't bother to terminate it and create a new one.
167+
schedule_drop(this);
142168
if is_call {
143169
block.unit()
144170
} else {
@@ -183,7 +209,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
183209
const_: Const::from_bool(this.tcx, constant),
184210
},
185211
);
186-
let mut rhs_block = unpack!(this.expr_into_dest(destination, continuation, rhs));
212+
let mut rhs_block =
213+
unpack!(this.expr_into_dest(destination, scope, continuation, rhs));
187214
// Instrument the lowered RHS's value for condition coverage.
188215
// (Does nothing if condition coverage is not enabled.)
189216
this.visit_coverage_standalone_condition(rhs, destination, &mut rhs_block);
@@ -209,53 +236,60 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
209236
// Start the loop.
210237
this.cfg.goto(block, source_info, loop_block);
211238

212-
this.in_breakable_scope(Some(loop_block), destination, expr_span, move |this| {
213-
// conduct the test, if necessary
214-
let body_block = this.cfg.start_new_block();
215-
this.cfg.terminate(
216-
loop_block,
217-
source_info,
218-
TerminatorKind::FalseUnwind {
219-
real_target: body_block,
220-
unwind: UnwindAction::Continue,
221-
},
222-
);
223-
this.diverge_from(loop_block);
224-
225-
// The “return” value of the loop body must always be a unit. We therefore
226-
// introduce a unit temporary as the destination for the loop body.
227-
let tmp = this.get_unit_temp();
228-
// Execute the body, branching back to the test.
229-
let body_block_end = unpack!(this.expr_into_dest(tmp, body_block, body));
230-
this.cfg.goto(body_block_end, source_info, loop_block);
231-
232-
// Loops are only exited by `break` expressions.
233-
None
234-
})
239+
this.in_breakable_scope(
240+
Some(loop_block),
241+
destination,
242+
scope,
243+
expr_span,
244+
move |this| {
245+
// conduct the test, if necessary
246+
let body_block = this.cfg.start_new_block();
247+
this.cfg.terminate(
248+
loop_block,
249+
source_info,
250+
TerminatorKind::FalseUnwind {
251+
real_target: body_block,
252+
unwind: UnwindAction::Continue,
253+
},
254+
);
255+
this.diverge_from(loop_block);
256+
257+
// The “return” value of the loop body must always be a unit. We therefore
258+
// introduce a unit temporary as the destination for the loop body.
259+
let tmp = this.get_unit_temp();
260+
// Execute the body, branching back to the test.
261+
let body_block_end =
262+
unpack!(this.expr_into_dest(tmp, scope, body_block, body));
263+
this.cfg.goto(body_block_end, source_info, loop_block);
264+
schedule_drop(this);
265+
266+
// Loops are only exited by `break` expressions.
267+
None
268+
},
269+
)
235270
}
236271
ExprKind::Call { ty: _, fun, ref args, from_hir_call, fn_span } => {
237272
let fun = unpack!(block = this.as_local_operand(block, fun));
238-
let args: Vec<_> = args
273+
let spanned_args: Vec<_> = args
239274
.into_iter()
240275
.copied()
241276
.map(|arg| Spanned {
242277
node: unpack!(block = this.as_local_call_operand(block, arg)),
243278
span: this.thir.exprs[arg].span,
244279
})
245280
.collect();
281+
let args: Vec<_> = spanned_args.iter().map(|arg| arg.node.clone()).collect();
246282

247283
let success = this.cfg.start_new_block();
248284

249-
this.record_operands_moved(&args);
250-
251285
debug!("expr_into_dest: fn_span={:?}", fn_span);
252286

253287
this.cfg.terminate(
254288
block,
255289
source_info,
256290
TerminatorKind::Call {
257291
func: fun,
258-
args,
292+
args: spanned_args,
259293
unwind: UnwindAction::Continue,
260294
destination,
261295
// The presence or absence of a return edge affects control-flow sensitive
@@ -275,9 +309,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
275309
},
276310
);
277311
this.diverge_from(block);
312+
313+
// This is here and not before `diverge_from` to avoid breaking
314+
// the example in #80949.
315+
// FIXME(matthewjasper): Look at this again if Polonius is
316+
// stabilized.
317+
this.record_operands_moved(&args);
318+
schedule_drop(this);
278319
success.unit()
279320
}
280-
ExprKind::Use { source } => this.expr_into_dest(destination, block, source),
321+
ExprKind::Use { source } => this.expr_into_dest(destination, scope, block, source),
281322
ExprKind::Borrow { arg, borrow_kind } => {
282323
// We don't do this in `as_rvalue` because we use `as_place`
283324
// for borrow expressions, so we cannot create an `RValue` that
@@ -340,7 +381,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
340381

341382
let field_names = adt_def.variant(variant_index).fields.indices();
342383

343-
let fields = if let Some(FruInfo { base, field_types }) = base {
384+
let fields: IndexVec<_, _> = if let Some(FruInfo { base, field_types }) = base {
344385
let place_builder = unpack!(block = this.as_place_builder(block, *base));
345386

346387
// MIR does not natively support FRU, so for each
@@ -374,12 +415,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
374415
user_ty,
375416
active_field_index,
376417
));
418+
this.record_operands_moved(&fields.raw);
377419
this.cfg.push_assign(
378420
block,
379421
source_info,
380422
destination,
381423
Rvalue::Aggregate(adt, fields),
382424
);
425+
schedule_drop(this);
383426
block.unit()
384427
}
385428
ExprKind::InlineAsm(box InlineAsmExpr {
@@ -458,7 +501,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
458501
targets.push(target);
459502

460503
let tmp = this.get_unit_temp();
461-
let target = unpack!(this.ast_block(tmp, target, block, source_info));
504+
let target =
505+
unpack!(this.ast_block(tmp, scope, target, block, source_info));
462506
this.cfg.terminate(
463507
target,
464508
source_info,
@@ -522,6 +566,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
522566
let place = unpack!(block = this.as_place(block, expr_id));
523567
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
524568
this.cfg.push_assign(block, source_info, destination, rvalue);
569+
schedule_drop(this);
525570
block.unit()
526571
}
527572
ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => {
@@ -537,6 +582,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
537582
let place = unpack!(block = this.as_place(block, expr_id));
538583
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
539584
this.cfg.push_assign(block, source_info, destination, rvalue);
585+
schedule_drop(this);
540586
block.unit()
541587
}
542588

@@ -552,12 +598,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
552598
)
553599
);
554600
let resume = this.cfg.start_new_block();
601+
this.record_operands_moved(slice::from_ref(&value));
555602
this.cfg.terminate(
556603
block,
557604
source_info,
558605
TerminatorKind::Yield { value, resume, resume_arg: destination, drop: None },
559606
);
560607
this.coroutine_drop_cleanup(block);
608+
schedule_drop(this);
561609
resume.unit()
562610
}
563611

@@ -594,6 +642,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
594642

595643
let rvalue = unpack!(block = this.as_local_rvalue(block, expr_id));
596644
this.cfg.push_assign(block, source_info, destination, rvalue);
645+
schedule_drop(this);
597646
block.unit()
598647
}
599648
};

‎compiler/rustc_mir_build/src/build/matches/mod.rs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
297297
pub(crate) fn match_expr(
298298
&mut self,
299299
destination: Place<'tcx>,
300+
destination_scope: Option<region::Scope>,
300301
mut block: BasicBlock,
301302
scrutinee_id: ExprId,
302303
arms: &[ArmId],
@@ -325,6 +326,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
325326

326327
self.lower_match_arms(
327328
destination,
329+
destination_scope,
328330
scrutinee_place,
329331
scrutinee_span,
330332
arm_candidates,
@@ -461,20 +463,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
461463
/// (by [Builder::lower_match_tree]).
462464
///
463465
/// `outer_source_info` is the SourceInfo for the whole match.
466+
/// [Builder::lower_match_tree]).
464467
fn lower_match_arms(
465468
&mut self,
466469
destination: Place<'tcx>,
470+
destination_scope: Option<region::Scope>,
467471
scrutinee_place_builder: PlaceBuilder<'tcx>,
468472
scrutinee_span: Span,
469473
arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>,
470474
outer_source_info: SourceInfo,
471475
fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)>,
472476
) -> BlockAnd<()> {
477+
if arm_candidates.is_empty() {
478+
// If there are no arms to schedule drops, then we have to do it
479+
// manually.
480+
if let Some(scope) = destination_scope {
481+
self.schedule_drop(
482+
outer_source_info.span,
483+
scope,
484+
destination.as_local().unwrap(),
485+
DropKind::Value,
486+
);
487+
}
488+
return self.cfg.start_new_block().unit();
489+
}
490+
491+
let mut first_arm = true;
473492
let arm_end_blocks: Vec<_> = arm_candidates
474493
.into_iter()
475494
.map(|(arm, candidate)| {
476495
debug!("lowering arm {:?}\ncandidate = {:?}", arm, candidate);
477496

497+
if first_arm {
498+
first_arm = false;
499+
} else if let Some(scope) = destination_scope {
500+
self.unschedule_drop(scope, destination.as_local().unwrap());
501+
}
502+
478503
let arm_source_info = self.source_info(arm.span);
479504
let arm_scope = (arm.scope, arm_source_info);
480505
let match_scope = self.local_scope();
@@ -519,7 +544,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
519544
this.source_scope = source_scope;
520545
}
521546

522-
this.expr_into_dest(destination, arm_block, arm.body)
547+
this.expr_into_dest(destination, destination_scope, arm_block, arm.body)
523548
})
524549
})
525550
.collect();
@@ -635,13 +660,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
635660
PatKind::Binding { mode: BindingMode(ByRef::No, _), var, subpattern: None, .. } => {
636661
let place =
637662
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
638-
unpack!(block = self.expr_into_dest(place, block, initializer_id));
663+
let region_scope = self.region_scope_tree.var_scope(var.0.local_id);
664+
665+
unpack!(block = self.expr_into_dest(place, region_scope, block, initializer_id));
639666

640667
// Inject a fake read, see comments on `FakeReadCause::ForLet`.
641668
let source_info = self.source_info(irrefutable_pat.span);
642669
self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet(None), place);
643670

644-
self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard);
645671
block.unit()
646672
}
647673

@@ -667,9 +693,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
667693
},
668694
ascription: thir::Ascription { ref annotation, variance: _ },
669695
} => {
696+
let region_scope = self.region_scope_tree.var_scope(var.0.local_id);
670697
let place =
671698
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
672-
unpack!(block = self.expr_into_dest(place, block, initializer_id));
699+
unpack!(block = self.expr_into_dest(place, region_scope, block, initializer_id));
673700

674701
// Inject a fake read, see comments on `FakeReadCause::ForLet`.
675702
let pattern_source_info = self.source_info(irrefutable_pat.span);
@@ -704,7 +731,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
704731
},
705732
);
706733

707-
self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard);
708734
block.unit()
709735
}
710736

‎compiler/rustc_mir_build/src/build/mod.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -521,15 +521,21 @@ fn construct_fn<'tcx>(
521521
let arg_scope_s = (arg_scope, source_info);
522522
// Attribute epilogue to function's closing brace
523523
let fn_end = span_with_body.shrink_to_hi();
524-
let return_block =
525-
unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| {
524+
let return_block = unpack!(builder.in_breakable_scope(
525+
None,
526+
Place::return_place(),
527+
Some(call_site_scope),
528+
fn_end,
529+
|builder| {
526530
Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
527531
builder.args_and_body(START_BLOCK, arguments, arg_scope, expr)
528532
}))
529-
}));
533+
},
534+
));
530535
let source_info = builder.source_info(fn_end);
531536
builder.cfg.terminate(return_block, source_info, TerminatorKind::Return);
532537
builder.build_drop_trees();
538+
builder.unschedule_return_place_drop();
533539
return_block.unit()
534540
}));
535541

@@ -577,7 +583,7 @@ fn construct_const<'a, 'tcx>(
577583
Builder::new(thir, infcx, def, hir_id, span, 0, const_ty, const_ty_span, None);
578584

579585
let mut block = START_BLOCK;
580-
unpack!(block = builder.expr_into_dest(Place::return_place(), block, expr));
586+
unpack!(block = builder.expr_into_dest(Place::return_place(), None, block, expr));
581587

582588
let source_info = builder.source_info(span);
583589
builder.cfg.terminate(block, source_info, TerminatorKind::Return);
@@ -974,7 +980,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
974980
self.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
975981
self.cfg.start_new_block().unit()
976982
} else {
977-
self.expr_into_dest(Place::return_place(), block, expr_id)
983+
let body = self.tcx.hir().body_owned_by(self.def_id);
984+
let call_site_scope =
985+
region::Scope { id: body.id().hir_id.local_id, data: region::ScopeData::CallSite };
986+
self.expr_into_dest(Place::return_place(), Some(call_site_scope), block, expr_id)
978987
}
979988
}
980989

‎compiler/rustc_mir_build/src/build/scope.rs

Lines changed: 89 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ use rustc_middle::mir::*;
9292
use rustc_middle::thir::{ExprId, LintLevel};
9393
use rustc_middle::{bug, span_bug};
9494
use rustc_session::lint::Level;
95-
use rustc_span::source_map::Spanned;
9695
use rustc_span::{Span, DUMMY_SP};
9796
use tracing::{debug, instrument};
9897

@@ -128,8 +127,6 @@ struct Scope {
128127
/// end of the vector (top of the stack) first.
129128
drops: Vec<DropData>,
130129

131-
moved_locals: Vec<Local>,
132-
133130
/// The drop index that will drop everything in and below this scope on an
134131
/// unwind path.
135132
cached_unwind_block: Option<DropIdx>,
@@ -165,6 +162,8 @@ struct BreakableScope<'tcx> {
165162
/// The destination of the loop/block expression itself (i.e., where to put
166163
/// the result of a `break` or `return` expression)
167164
break_destination: Place<'tcx>,
165+
/// The scope that the destination should have its drop scheduled in.
166+
destination_scope: Option<region::Scope>,
168167
/// Drops that happen on the `break`/`return` path.
169168
break_drops: DropTree,
170169
/// Drops that happen on the `continue` path.
@@ -445,7 +444,6 @@ impl<'tcx> Scopes<'tcx> {
445444
source_scope: vis_scope,
446445
region_scope: region_scope.0,
447446
drops: vec![],
448-
moved_locals: vec![],
449447
cached_unwind_block: None,
450448
cached_coroutine_drop_block: None,
451449
});
@@ -481,6 +479,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
481479
&mut self,
482480
loop_block: Option<BasicBlock>,
483481
break_destination: Place<'tcx>,
482+
destination_scope: Option<region::Scope>,
484483
span: Span,
485484
f: F,
486485
) -> BlockAnd<()>
@@ -491,17 +490,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
491490
let scope = BreakableScope {
492491
region_scope,
493492
break_destination,
493+
destination_scope,
494494
break_drops: DropTree::new(),
495495
continue_drops: loop_block.map(|_| DropTree::new()),
496496
};
497+
let continue_block = loop_block.map(|block| (block, self.diverge_cleanup()));
497498
self.scopes.breakable_scopes.push(scope);
498499
let normal_exit_block = f(self);
499500
let breakable_scope = self.scopes.breakable_scopes.pop().unwrap();
500501
assert!(breakable_scope.region_scope == region_scope);
501502
let break_block =
502503
self.build_exit_tree(breakable_scope.break_drops, region_scope, span, None);
503504
if let Some(drops) = breakable_scope.continue_drops {
504-
self.build_exit_tree(drops, region_scope, span, loop_block);
505+
self.build_exit_tree(drops, region_scope, span, continue_block);
505506
}
506507
match (normal_exit_block, break_block) {
507508
(Some(block), None) | (None, Some(block)) => block,
@@ -634,30 +635,33 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
634635
.rposition(|breakable_scope| breakable_scope.region_scope == scope)
635636
.unwrap_or_else(|| span_bug!(span, "no enclosing breakable scope found"))
636637
};
637-
let (break_index, destination) = match target {
638+
let (break_index, destination, dest_scope) = match target {
638639
BreakableTarget::Return => {
639640
let scope = &self.scopes.breakable_scopes[0];
640641
if scope.break_destination != Place::return_place() {
641642
span_bug!(span, "`return` in item with no return scope");
642643
}
643-
(0, Some(scope.break_destination))
644+
(0, Some(scope.break_destination), scope.destination_scope)
644645
}
645646
BreakableTarget::Break(scope) => {
646647
let break_index = get_scope_index(scope);
647648
let scope = &self.scopes.breakable_scopes[break_index];
648-
(break_index, Some(scope.break_destination))
649+
(break_index, Some(scope.break_destination), scope.destination_scope)
649650
}
650651
BreakableTarget::Continue(scope) => {
651652
let break_index = get_scope_index(scope);
652-
(break_index, None)
653+
(break_index, None, None)
653654
}
654655
};
655656

656657
match (destination, value) {
657658
(Some(destination), Some(value)) => {
658659
debug!("stmt_expr Break val block_context.push(SubExpr)");
659660
self.block_context.push(BlockFrame::SubExpr);
660-
unpack!(block = self.expr_into_dest(destination, block, value));
661+
unpack!(block = self.expr_into_dest(destination, dest_scope, block, value));
662+
if let Some(scope) = dest_scope {
663+
self.unschedule_drop(scope, destination.as_local().unwrap())
664+
};
661665
self.block_context.pop();
662666
}
663667
(Some(destination), None) => {
@@ -1014,17 +1018,56 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
10141018
}
10151019
}
10161020

1017-
span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local);
1021+
span_bug!(
1022+
span,
1023+
"region scope {:?} not in scope to drop {:?}\n{:#?}",
1024+
region_scope,
1025+
local,
1026+
self.scopes.scopes
1027+
);
1028+
}
1029+
1030+
/// Unschedule a drop. Used for `break`, `return` and `match` expressions,
1031+
/// where `record_operands_moved` is not powerful enough.
1032+
///
1033+
/// The given local is expected to have a value drop scheduled in the given
1034+
/// scope and for that drop to be the most recent thing scheduled in that
1035+
/// scope.
1036+
pub(crate) fn unschedule_drop(&mut self, region_scope: region::Scope, local: Local) {
1037+
if !self.local_decls[local].ty.needs_drop(self.tcx, self.param_env) {
1038+
return;
1039+
}
1040+
for scope in self.scopes.scopes.iter_mut().rev() {
1041+
scope.invalidate_cache();
1042+
1043+
if scope.region_scope == region_scope {
1044+
let drop = scope.drops.pop();
1045+
1046+
match drop {
1047+
Some(DropData { local: removed_local, kind: DropKind::Value, .. })
1048+
if removed_local == local =>
1049+
{
1050+
return;
1051+
}
1052+
_ => bug!(
1053+
"found wrong drop, expected value drop of {:?}, found {:?}",
1054+
local,
1055+
drop,
1056+
),
1057+
}
1058+
}
1059+
}
1060+
1061+
bug!("region scope {:?} not in scope to unschedule drop of {:?}", region_scope, local);
10181062
}
10191063

1020-
/// Indicates that the "local operand" stored in `local` is
1064+
/// Indicates that the "local operands" stored in `local` are
10211065
/// *moved* at some point during execution (see `local_scope` for
10221066
/// more information about what a "local operand" is -- in short,
10231067
/// it's an intermediate operand created as part of preparing some
10241068
/// MIR instruction). We use this information to suppress
1025-
/// redundant drops on the non-unwind paths. This results in less
1026-
/// MIR, but also avoids spurious borrow check errors
1027-
/// (c.f. #64391).
1069+
/// redundant drops. This results in less MIR, but also avoids spurious
1070+
/// borrow check errors (c.f. #64391).
10281071
///
10291072
/// Example: when compiling the call to `foo` here:
10301073
///
@@ -1053,27 +1096,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
10531096
/// spurious borrow-check errors -- the problem, ironically, is
10541097
/// not the `DROP(_X)` itself, but the (spurious) unwind pathways
10551098
/// that it creates. See #64391 for an example.
1056-
pub(crate) fn record_operands_moved(&mut self, operands: &[Spanned<Operand<'tcx>>]) {
1099+
pub(crate) fn record_operands_moved(&mut self, operands: &[Operand<'tcx>]) {
10571100
let local_scope = self.local_scope();
10581101
let scope = self.scopes.scopes.last_mut().unwrap();
10591102

10601103
assert_eq!(scope.region_scope, local_scope, "local scope is not the topmost scope!",);
10611104

10621105
// look for moves of a local variable, like `MOVE(_X)`
1063-
let locals_moved = operands.iter().flat_map(|operand| match operand.node {
1106+
let locals_moved = operands.iter().flat_map(|operand| match operand {
10641107
Operand::Copy(_) | Operand::Constant(_) => None,
10651108
Operand::Move(place) => place.as_local(),
10661109
});
10671110

10681111
for local in locals_moved {
1069-
// check if we have a Drop for this operand and -- if so
1070-
// -- add it to the list of moved operands. Note that this
1071-
// local might not have been an operand created for this
1072-
// call, it could come from other places too.
1073-
if scope.drops.iter().any(|drop| drop.local == local && drop.kind == DropKind::Value) {
1074-
scope.moved_locals.push(local);
1075-
}
1112+
// Unschedule drops from the scope.
1113+
scope.drops.retain(|drop| drop.local != local || drop.kind != DropKind::Value);
10761114
}
1115+
scope.invalidate_cache();
10771116
}
10781117

10791118
// Other
@@ -1251,6 +1290,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12511290
top_scope.drops.clear();
12521291
top_scope.invalidate_cache();
12531292
}
1293+
1294+
/// Unschedules the drop of the return place.
1295+
///
1296+
/// If the return type of a function requires drop, then we schedule it
1297+
/// in the outermost scope so that it's dropped if there's a panic while
1298+
/// we drop any local variables. But we don't want to drop it if we
1299+
/// return normally.
1300+
pub(crate) fn unschedule_return_place_drop(&mut self) {
1301+
assert_eq!(self.scopes.scopes.len(), 1);
1302+
assert!(
1303+
self.scopes.scopes[0].drops.len() <= 1,
1304+
"Found too many drops: {:?}",
1305+
self.scopes.scopes[0].drops
1306+
);
1307+
self.scopes.scopes[0].drops.clear();
1308+
}
12541309
}
12551310

12561311
/// Builds drops for `pop_scope` and `leave_top_scope`.
@@ -1297,14 +1352,6 @@ fn build_scope_drops<'tcx>(
12971352
debug_assert_eq!(unwind_drops.drops[unwind_to].data.kind, drop_data.kind);
12981353
unwind_to = unwind_drops.drops[unwind_to].next;
12991354

1300-
// If the operand has been moved, and we are not on an unwind
1301-
// path, then don't generate the drop. (We only take this into
1302-
// account for non-unwind paths so as not to disturb the
1303-
// caching mechanism.)
1304-
if scope.moved_locals.iter().any(|&o| o == local) {
1305-
continue;
1306-
}
1307-
13081355
unwind_drops.add_entry_point(block, unwind_to);
13091356

13101357
let next = cfg.start_new_block();
@@ -1339,23 +1386,29 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
13391386
/// Build a drop tree for a breakable scope.
13401387
///
13411388
/// If `continue_block` is `Some`, then the tree is for `continue` inside a
1342-
/// loop. Otherwise this is for `break` or `return`.
1389+
/// loop. Otherwise this is for `break` or `return`. The `DropIdx` is the
1390+
/// next drop in the case that the drop tree unwinds. This is needed
1391+
/// because the drop of the break destination has already been scheduled
1392+
/// but it hasn't been initialized on the `continue` paths.
13431393
fn build_exit_tree(
13441394
&mut self,
13451395
mut drops: DropTree,
13461396
else_scope: region::Scope,
13471397
span: Span,
1348-
continue_block: Option<BasicBlock>,
1398+
continue_block: Option<(BasicBlock, DropIdx)>,
13491399
) -> Option<BlockAnd<()>> {
13501400
let mut blocks = IndexVec::from_elem(None, &drops.drops);
1351-
blocks[ROOT_NODE] = continue_block;
1401+
blocks[ROOT_NODE] = continue_block.map(|(block, _)| block);
13521402

13531403
drops.build_mir::<ExitScopes>(&mut self.cfg, &mut blocks);
13541404
let is_coroutine = self.coroutine.is_some();
13551405

13561406
// Link the exit drop tree to unwind drop tree.
13571407
if drops.drops.iter().any(|drop_node| drop_node.data.kind == DropKind::Value) {
1358-
let unwind_target = self.diverge_cleanup_target(else_scope, span);
1408+
let unwind_target = continue_block.map_or_else(
1409+
|| self.diverge_cleanup_target(else_scope, span),
1410+
|(_, unwind_target)| unwind_target,
1411+
);
13591412
let mut unwind_indices = IndexVec::from_elem_n(unwind_target, 1);
13601413
for (drop_idx, drop_node) in drops.drops.iter_enumerated().skip(1) {
13611414
match drop_node.data.kind {

‎library/alloc/src/collections/btree/map/tests.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2104,6 +2104,7 @@ create_append_test!(test_append_1700, 1700);
21042104

21052105
#[test]
21062106
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
2107+
#[cfg_attr(bootstrap, ignore = "test requires compiler fix from current nightly")]
21072108
fn test_append_drop_leak() {
21082109
let a = CrashTestDummy::new(0);
21092110
let b = CrashTestDummy::new(1);
@@ -2118,7 +2119,7 @@ fn test_append_drop_leak() {
21182119

21192120
catch_unwind(move || left.append(&mut right)).unwrap_err();
21202121
assert_eq!(a.dropped(), 1);
2121-
assert_eq!(b.dropped(), 1); // should be 2 were it not for Rust issue #47949
2122+
assert_eq!(b.dropped(), 2);
21222123
assert_eq!(c.dropped(), 2);
21232124
}
21242125

‎tests/mir-opt/box_expr.main.ElaborateDrops.diff

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,62 +26,57 @@
2626
bb1: {
2727
StorageLive(_5);
2828
_5 = ShallowInitBox(move _4, S);
29-
(*_5) = S::new() -> [return: bb2, unwind: bb8];
29+
(*_5) = S::new() -> [return: bb2, unwind: bb7];
3030
}
3131

3232
bb2: {
3333
_1 = move _5;
34-
- drop(_5) -> [return: bb3, unwind continue];
35-
+ goto -> bb3;
36-
}
37-
38-
bb3: {
3934
StorageDead(_5);
4035
StorageLive(_6);
4136
StorageLive(_7);
4237
_7 = move _1;
43-
_6 = std::mem::drop::<Box<S>>(move _7) -> [return: bb4, unwind: bb6];
38+
_6 = std::mem::drop::<Box<S>>(move _7) -> [return: bb3, unwind: bb5];
4439
}
4540

46-
bb4: {
41+
bb3: {
4742
StorageDead(_7);
4843
StorageDead(_6);
4944
_0 = const ();
50-
- drop(_1) -> [return: bb5, unwind continue];
51-
+ goto -> bb5;
45+
- drop(_1) -> [return: bb4, unwind continue];
46+
+ goto -> bb4;
5247
}
5348

54-
bb5: {
49+
bb4: {
5550
StorageDead(_1);
5651
return;
5752
}
5853

54+
bb5 (cleanup): {
55+
- drop(_7) -> [return: bb6, unwind terminate(cleanup)];
56+
+ goto -> bb6;
57+
}
58+
5959
bb6 (cleanup): {
60-
- drop(_7) -> [return: bb7, unwind terminate(cleanup)];
61-
+ goto -> bb7;
60+
- drop(_1) -> [return: bb8, unwind terminate(cleanup)];
61+
+ goto -> bb8;
6262
}
6363

6464
bb7 (cleanup): {
65-
- drop(_1) -> [return: bb9, unwind terminate(cleanup)];
66-
+ goto -> bb9;
65+
- drop(_5) -> [return: bb8, unwind terminate(cleanup)];
66+
+ goto -> bb10;
6767
}
6868

6969
bb8 (cleanup): {
70-
- drop(_5) -> [return: bb9, unwind terminate(cleanup)];
71-
+ goto -> bb11;
72-
}
73-
74-
bb9 (cleanup): {
7570
resume;
7671
+ }
7772
+
78-
+ bb10 (cleanup): {
73+
+ bb9 (cleanup): {
7974
+ _8 = &mut _5;
80-
+ _9 = <Box<S> as Drop>::drop(move _8) -> [return: bb9, unwind terminate(cleanup)];
75+
+ _9 = <Box<S> as Drop>::drop(move _8) -> [return: bb8, unwind terminate(cleanup)];
8176
+ }
8277
+
83-
+ bb11 (cleanup): {
84-
+ goto -> bb10;
78+
+ bb10 (cleanup): {
79+
+ goto -> bb9;
8580
}
8681
}
8782

‎tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir

Lines changed: 15 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -26,86 +26,66 @@ fn move_out_by_subslice() -> () {
2626
StorageLive(_2);
2727
_3 = SizeOf(i32);
2828
_4 = AlignOf(i32);
29-
_5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb14];
29+
_5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb9];
3030
}
3131

3232
bb1: {
3333
StorageLive(_6);
3434
_6 = ShallowInitBox(move _5, i32);
3535
(*_6) = const 1_i32;
3636
_2 = move _6;
37-
drop(_6) -> [return: bb2, unwind: bb13];
38-
}
39-
40-
bb2: {
4137
StorageDead(_6);
4238
StorageLive(_7);
4339
_8 = SizeOf(i32);
4440
_9 = AlignOf(i32);
45-
_10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb13];
41+
_10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb2, unwind: bb8];
4642
}
4743

48-
bb3: {
44+
bb2: {
4945
StorageLive(_11);
5046
_11 = ShallowInitBox(move _10, i32);
5147
(*_11) = const 2_i32;
5248
_7 = move _11;
53-
drop(_11) -> [return: bb4, unwind: bb12];
54-
}
55-
56-
bb4: {
5749
StorageDead(_11);
5850
_1 = [move _2, move _7];
59-
drop(_7) -> [return: bb5, unwind: bb13];
60-
}
61-
62-
bb5: {
6351
StorageDead(_7);
64-
drop(_2) -> [return: bb6, unwind: bb14];
65-
}
66-
67-
bb6: {
6852
StorageDead(_2);
6953
FakeRead(ForLet(None), _1);
7054
PlaceMention(_1);
7155
StorageLive(_12);
7256
_12 = move _1[0..2];
7357
_0 = const ();
74-
drop(_12) -> [return: bb9, unwind: bb11];
58+
drop(_12) -> [return: bb5, unwind: bb7];
7559
}
7660

77-
bb7: {
61+
bb3: {
7862
FakeRead(ForMatchedPlace(None), _1);
7963
unreachable;
8064
}
8165

82-
bb8: {
83-
goto -> bb7;
66+
bb4: {
67+
goto -> bb3;
8468
}
8569

86-
bb9: {
70+
bb5: {
8771
StorageDead(_12);
88-
drop(_1) -> [return: bb10, unwind: bb14];
72+
drop(_1) -> [return: bb6, unwind: bb9];
8973
}
9074

91-
bb10: {
75+
bb6: {
9276
StorageDead(_1);
9377
return;
9478
}
9579

96-
bb11 (cleanup): {
97-
drop(_1) -> [return: bb14, unwind terminate(cleanup)];
98-
}
99-
100-
bb12 (cleanup): {
101-
drop(_7) -> [return: bb13, unwind terminate(cleanup)];
80+
bb7 (cleanup): {
81+
drop(_1) -> [return: bb9, unwind terminate(cleanup)];
10282
}
10383

104-
bb13 (cleanup): {
105-
drop(_2) -> [return: bb14, unwind terminate(cleanup)];
84+
bb8 (cleanup): {
85+
drop(_2) -> [return: bb9, unwind terminate(cleanup)];
10686
}
10787

108-
bb14 (cleanup): {
88+
bb9 (cleanup): {
10989
resume;
11090
}
11191
}

‎tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir

Lines changed: 15 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -26,86 +26,66 @@ fn move_out_from_end() -> () {
2626
StorageLive(_2);
2727
_3 = SizeOf(i32);
2828
_4 = AlignOf(i32);
29-
_5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb14];
29+
_5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb9];
3030
}
3131

3232
bb1: {
3333
StorageLive(_6);
3434
_6 = ShallowInitBox(move _5, i32);
3535
(*_6) = const 1_i32;
3636
_2 = move _6;
37-
drop(_6) -> [return: bb2, unwind: bb13];
38-
}
39-
40-
bb2: {
4137
StorageDead(_6);
4238
StorageLive(_7);
4339
_8 = SizeOf(i32);
4440
_9 = AlignOf(i32);
45-
_10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb13];
41+
_10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb2, unwind: bb8];
4642
}
4743

48-
bb3: {
44+
bb2: {
4945
StorageLive(_11);
5046
_11 = ShallowInitBox(move _10, i32);
5147
(*_11) = const 2_i32;
5248
_7 = move _11;
53-
drop(_11) -> [return: bb4, unwind: bb12];
54-
}
55-
56-
bb4: {
5749
StorageDead(_11);
5850
_1 = [move _2, move _7];
59-
drop(_7) -> [return: bb5, unwind: bb13];
60-
}
61-
62-
bb5: {
6351
StorageDead(_7);
64-
drop(_2) -> [return: bb6, unwind: bb14];
65-
}
66-
67-
bb6: {
6852
StorageDead(_2);
6953
FakeRead(ForLet(None), _1);
7054
PlaceMention(_1);
7155
StorageLive(_12);
7256
_12 = move _1[1 of 2];
7357
_0 = const ();
74-
drop(_12) -> [return: bb9, unwind: bb11];
58+
drop(_12) -> [return: bb5, unwind: bb7];
7559
}
7660

77-
bb7: {
61+
bb3: {
7862
FakeRead(ForMatchedPlace(None), _1);
7963
unreachable;
8064
}
8165

82-
bb8: {
83-
goto -> bb7;
66+
bb4: {
67+
goto -> bb3;
8468
}
8569

86-
bb9: {
70+
bb5: {
8771
StorageDead(_12);
88-
drop(_1) -> [return: bb10, unwind: bb14];
72+
drop(_1) -> [return: bb6, unwind: bb9];
8973
}
9074

91-
bb10: {
75+
bb6: {
9276
StorageDead(_1);
9377
return;
9478
}
9579

96-
bb11 (cleanup): {
97-
drop(_1) -> [return: bb14, unwind terminate(cleanup)];
98-
}
99-
100-
bb12 (cleanup): {
101-
drop(_7) -> [return: bb13, unwind terminate(cleanup)];
80+
bb7 (cleanup): {
81+
drop(_1) -> [return: bb9, unwind terminate(cleanup)];
10282
}
10383

104-
bb13 (cleanup): {
105-
drop(_2) -> [return: bb14, unwind terminate(cleanup)];
84+
bb8 (cleanup): {
85+
drop(_2) -> [return: bb9, unwind terminate(cleanup)];
10686
}
10787

108-
bb14 (cleanup): {
88+
bb9 (cleanup): {
10989
resume;
11090
}
11191
}

‎tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@
2929
+ StorageLive(_4);
3030
+ StorageLive(_3);
3131
+ _3 = &_2;
32-
+ _4 = <fn() -> ! {sleep} as Fn<()>>::call(move _3, const ()) -> [return: bb1, unwind: bb5];
32+
+ _4 = <fn() -> ! {sleep} as Fn<()>>::call(move _3, const ()) -> [return: bb1, unwind: bb6];
3333
+ }
3434
+
3535
+ bb1: {
3636
+ StorageDead(_3);
3737
+ StorageLive(_5);
3838
+ _5 = &_2;
39-
+ _6 = <fn() -> ! {sleep} as Fn<()>>::call(move _5, const ()) -> [return: bb2, unwind: bb4];
39+
+ _6 = <fn() -> ! {sleep} as Fn<()>>::call(move _5, const ()) -> [return: bb2, unwind: bb5];
4040
+ }
4141
+
4242
+ bb2: {
@@ -46,22 +46,26 @@
4646
+ _1 = (move _7, _6);
4747
+ StorageDead(_7);
4848
+ StorageDead(_4);
49-
+ drop(_2) -> [return: bb3, unwind continue];
49+
+ drop(_2) -> [return: bb3, unwind: bb4];
5050
+ }
5151
+
5252
+ bb3: {
5353
+ unreachable;
5454
+ }
5555
+
5656
+ bb4 (cleanup): {
57-
+ drop(_4) -> [return: bb5, unwind terminate(cleanup)];
57+
+ drop(_1) -> [return: bb7, unwind terminate(cleanup)];
5858
+ }
5959
+
6060
+ bb5 (cleanup): {
61-
+ drop(_2) -> [return: bb6, unwind terminate(cleanup)];
61+
+ drop(_4) -> [return: bb6, unwind terminate(cleanup)];
6262
+ }
6363
+
6464
+ bb6 (cleanup): {
65+
+ drop(_2) -> [return: bb7, unwind terminate(cleanup)];
66+
+ }
67+
+
68+
+ bb7 (cleanup): {
6569
+ resume;
6670
}
6771
}

‎tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-abort.mir

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ fn test() -> Option<Box<u32>> {
2929
StorageLive(_1);
3030
_2 = SizeOf(u32);
3131
_3 = AlignOf(u32);
32-
_4 = alloc::alloc::exchange_malloc(move _2, move _3) -> [return: bb1, unwind: bb13];
32+
_4 = alloc::alloc::exchange_malloc(move _2, move _3) -> [return: bb1, unwind: bb11];
3333
}
3434

3535
bb1: {
@@ -38,7 +38,7 @@ fn test() -> Option<Box<u32>> {
3838
StorageLive(_6);
3939
StorageLive(_7);
4040
_7 = Option::<u32>::None;
41-
_6 = <Option<u32> as Try>::branch(move _7) -> [return: bb2, unwind: bb12];
41+
_6 = <Option<u32> as Try>::branch(move _7) -> [return: bb2, unwind: bb10];
4242
}
4343

4444
bb2: {
@@ -58,55 +58,47 @@ fn test() -> Option<Box<u32>> {
5858
(*_5) = _12;
5959
StorageDead(_12);
6060
_1 = move _5;
61-
drop(_5) -> [return: bb7, unwind: bb11];
61+
StorageDead(_5);
62+
_0 = Option::<Box<u32>>::Some(move _1);
63+
StorageDead(_1);
64+
StorageDead(_6);
65+
goto -> bb8;
6266
}
6367

6468
bb5: {
6569
StorageLive(_9);
6670
_9 = ((_6 as Break).0: std::option::Option<std::convert::Infallible>);
6771
StorageLive(_11);
6872
_11 = _9;
69-
_0 = <Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual(move _11) -> [return: bb6, unwind: bb12];
73+
_0 = <Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual(move _11) -> [return: bb6, unwind: bb10];
7074
}
7175

7276
bb6: {
7377
StorageDead(_11);
7478
StorageDead(_9);
75-
drop(_5) -> [return: bb9, unwind: bb13];
79+
drop(_5) -> [return: bb7, unwind: bb9];
7680
}
7781

7882
bb7: {
79-
StorageDead(_5);
80-
_0 = Option::<Box<u32>>::Some(move _1);
81-
drop(_1) -> [return: bb8, unwind: bb13];
82-
}
83-
84-
bb8: {
85-
StorageDead(_1);
86-
StorageDead(_6);
87-
goto -> bb10;
88-
}
89-
90-
bb9: {
9183
StorageDead(_5);
9284
StorageDead(_1);
9385
StorageDead(_6);
94-
goto -> bb10;
86+
goto -> bb8;
9587
}
9688

97-
bb10: {
89+
bb8: {
9890
return;
9991
}
10092

101-
bb11 (cleanup): {
102-
drop(_1) -> [return: bb13, unwind terminate(cleanup)];
93+
bb9 (cleanup): {
94+
drop(_0) -> [return: bb11, unwind terminate(cleanup)];
10395
}
10496

105-
bb12 (cleanup): {
106-
drop(_5) -> [return: bb13, unwind terminate(cleanup)];
97+
bb10 (cleanup): {
98+
drop(_5) -> [return: bb11, unwind terminate(cleanup)];
10799
}
108100

109-
bb13 (cleanup): {
101+
bb11 (cleanup): {
110102
resume;
111103
}
112104
}

‎tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-unwind.mir

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ fn test() -> Option<Box<u32>> {
3838
StorageLive(_6);
3939
StorageLive(_7);
4040
_7 = Option::<u32>::None;
41-
_6 = <Option<u32> as Try>::branch(move _7) -> [return: bb2, unwind: bb12];
41+
_6 = <Option<u32> as Try>::branch(move _7) -> [return: bb2, unwind: bb10];
4242
}
4343

4444
bb2: {
@@ -58,55 +58,47 @@ fn test() -> Option<Box<u32>> {
5858
(*_5) = _12;
5959
StorageDead(_12);
6060
_1 = move _5;
61-
drop(_5) -> [return: bb7, unwind: bb11];
61+
StorageDead(_5);
62+
_0 = Option::<Box<u32>>::Some(move _1);
63+
StorageDead(_1);
64+
StorageDead(_6);
65+
goto -> bb8;
6266
}
6367

6468
bb5: {
6569
StorageLive(_9);
6670
_9 = ((_6 as Break).0: std::option::Option<std::convert::Infallible>);
6771
StorageLive(_11);
6872
_11 = _9;
69-
_0 = <Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual(move _11) -> [return: bb6, unwind: bb12];
73+
_0 = <Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual(move _11) -> [return: bb6, unwind: bb10];
7074
}
7175

7276
bb6: {
7377
StorageDead(_11);
7478
StorageDead(_9);
75-
drop(_5) -> [return: bb9, unwind continue];
79+
drop(_5) -> [return: bb7, unwind: bb9];
7680
}
7781

7882
bb7: {
79-
StorageDead(_5);
80-
_0 = Option::<Box<u32>>::Some(move _1);
81-
drop(_1) -> [return: bb8, unwind continue];
82-
}
83-
84-
bb8: {
85-
StorageDead(_1);
86-
StorageDead(_6);
87-
goto -> bb10;
88-
}
89-
90-
bb9: {
9183
StorageDead(_5);
9284
StorageDead(_1);
9385
StorageDead(_6);
94-
goto -> bb10;
86+
goto -> bb8;
9587
}
9688

97-
bb10: {
89+
bb8: {
9890
return;
9991
}
10092

101-
bb11 (cleanup): {
102-
drop(_1) -> [return: bb13, unwind terminate(cleanup)];
93+
bb9 (cleanup): {
94+
drop(_0) -> [return: bb11, unwind terminate(cleanup)];
10395
}
10496

105-
bb12 (cleanup): {
106-
drop(_5) -> [return: bb13, unwind terminate(cleanup)];
97+
bb10 (cleanup): {
98+
drop(_5) -> [return: bb11, unwind terminate(cleanup)];
10799
}
108100

109-
bb13 (cleanup): {
101+
bb11 (cleanup): {
110102
resume;
111103
}
112104
}

‎tests/mir-opt/issue_91633.foo.built.after.mir

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ fn foo(_1: Box<[T]>) -> T {
1919
_4 = const 0_usize;
2020
_5 = Len((*_1));
2121
_6 = Lt(_4, _5);
22-
assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind: bb5];
22+
assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind: bb7];
2323
}
2424

2525
bb1: {
2626
_3 = &(*_1)[_4];
27-
_2 = <T as Clone>::clone(move _3) -> [return: bb2, unwind: bb5];
27+
_2 = <T as Clone>::clone(move _3) -> [return: bb2, unwind: bb7];
2828
}
2929

3030
bb2: {
@@ -49,6 +49,14 @@ fn foo(_1: Box<[T]>) -> T {
4949
}
5050

5151
bb6 (cleanup): {
52+
drop(_0) -> [return: bb8, unwind terminate(cleanup)];
53+
}
54+
55+
bb7 (cleanup): {
56+
drop(_1) -> [return: bb8, unwind terminate(cleanup)];
57+
}
58+
59+
bb8 (cleanup): {
5260
resume;
5361
}
5462
}

‎tests/mir-opt/sroa/structs.dropping.ScalarReplacementOfAggregates.diff

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,22 @@
2323
StorageDead(_4);
2424
StorageDead(_3);
2525
_1 = move (_2.1: Tag);
26-
drop(_1) -> [return: bb1, unwind unreachable];
26+
drop(_1) -> [return: bb3, unwind unreachable];
2727
}
2828

2929
bb1: {
30-
drop((_2.0: Tag)) -> [return: bb3, unwind unreachable];
31-
}
32-
33-
bb2: {
3430
StorageDead(_2);
3531
StorageDead(_1);
3632
_0 = const ();
3733
return;
3834
}
3935

36+
bb2: {
37+
drop((_2.2: Tag)) -> [return: bb1, unwind unreachable];
38+
}
39+
4040
bb3: {
41-
drop((_2.2: Tag)) -> [return: bb2, unwind unreachable];
41+
drop((_2.0: Tag)) -> [return: bb2, unwind unreachable];
4242
}
4343
}
4444

‎tests/ui/deriving/deriving-with-helper.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ mod default {
2929
#[lang = "sized"]
3030
trait Sized {}
3131

32+
#[lang = "copy"]
33+
trait Copy: Sized {}
34+
3235
#[derive(Default)]
3336
enum S {
3437
#[default] // OK

‎tests/ui/drop/dynamic-drop-async.rs

Lines changed: 111 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ impl<T: Unpin> Future for Defer<T> {
4343
/// The `failing_op`-th operation will panic.
4444
struct Allocator {
4545
data: RefCell<Vec<bool>>,
46+
name: &'static str,
4647
failing_op: usize,
4748
cur_ops: Cell<usize>,
4849
}
@@ -54,23 +55,28 @@ impl Drop for Allocator {
5455
fn drop(&mut self) {
5556
let data = self.data.borrow();
5657
if data.iter().any(|d| *d) {
57-
panic!("missing free: {:?}", data);
58+
panic!("missing free in {:?}: {:?}", self.name, data);
5859
}
5960
}
6061
}
6162

6263
impl Allocator {
63-
fn new(failing_op: usize) -> Self {
64-
Allocator { failing_op, cur_ops: Cell::new(0), data: RefCell::new(vec![]) }
64+
fn new(failing_op: usize, name: &'static str) -> Self {
65+
Allocator {
66+
failing_op,
67+
name,
68+
cur_ops: Cell::new(0),
69+
data: RefCell::new(vec![]),
70+
}
6571
}
66-
fn alloc(&self) -> impl Future<Output = Ptr<'_>> + '_ {
72+
fn alloc(self: &Rc<Allocator>) -> impl Future<Output = Ptr> + 'static {
6773
self.fallible_operation();
6874

6975
let mut data = self.data.borrow_mut();
7076

7177
let addr = data.len();
7278
data.push(true);
73-
Defer { ready: false, value: Some(Ptr(addr, self)) }
79+
Defer { ready: false, value: Some(Ptr(addr, self.clone())) }
7480
}
7581
fn fallible_operation(&self) {
7682
self.cur_ops.set(self.cur_ops.get() + 1);
@@ -83,11 +89,11 @@ impl Allocator {
8389

8490
// Type that tracks whether it was dropped and can panic when it's created or
8591
// destroyed.
86-
struct Ptr<'a>(usize, &'a Allocator);
87-
impl<'a> Drop for Ptr<'a> {
92+
struct Ptr(usize, Rc<Allocator>);
93+
impl Drop for Ptr {
8894
fn drop(&mut self) {
8995
match self.1.data.borrow_mut()[self.0] {
90-
false => panic!("double free at index {:?}", self.0),
96+
false => panic!("double free in {:?} at index {:?}", self.1.name, self.0),
9197
ref mut d => *d = false,
9298
}
9399

@@ -111,7 +117,7 @@ async fn dynamic_drop(a: Rc<Allocator>, c: bool) {
111117
};
112118
}
113119

114-
struct TwoPtrs<'a>(Ptr<'a>, Ptr<'a>);
120+
struct TwoPtrs(Ptr, Ptr);
115121
async fn struct_dynamic_drop(a: Rc<Allocator>, c0: bool, c1: bool, c: bool) {
116122
for i in 0..2 {
117123
let x;
@@ -232,21 +238,62 @@ async fn move_ref_pattern(a: Rc<Allocator>) {
232238
a.alloc().await;
233239
}
234240

235-
fn run_test<F, G>(cx: &mut Context<'_>, ref f: F)
241+
async fn panic_after_return(a: Rc<Allocator>, c: bool) -> (Ptr,) {
242+
a.alloc().await;
243+
let p = a.alloc().await;
244+
if c {
245+
a.alloc().await;
246+
let q = a.alloc().await;
247+
// We use a return type that isn't used anywhere else to make sure that
248+
// the return place doesn't incorrectly end up in the generator state.
249+
return (a.alloc().await,);
250+
}
251+
(a.alloc().await,)
252+
}
253+
254+
255+
async fn panic_after_init_by_loop(a: Rc<Allocator>) {
256+
a.alloc().await;
257+
let p = a.alloc().await;
258+
let q = loop {
259+
a.alloc().await;
260+
let r = a.alloc().await;
261+
break a.alloc().await;
262+
};
263+
}
264+
265+
async fn panic_after_init_by_match_with_bindings_and_guard(a: Rc<Allocator>, b: bool) {
266+
a.alloc().await;
267+
let p = a.alloc().await;
268+
let q = match a.alloc().await {
269+
ref _x if b => {
270+
a.alloc().await;
271+
let r = a.alloc().await;
272+
a.alloc().await
273+
}
274+
_x => {
275+
a.alloc().await;
276+
let r = a.alloc().await;
277+
a.alloc().await
278+
},
279+
};
280+
}
281+
282+
fn run_test<F, G, O>(cx: &mut Context<'_>, ref f: F, name: &'static str)
236283
where
237284
F: Fn(Rc<Allocator>) -> G,
238-
G: Future<Output = ()>,
285+
G: Future<Output = O>,
239286
{
240287
for polls in 0.. {
241288
// Run without any panics to find which operations happen after the
242289
// penultimate `poll`.
243-
let first_alloc = Rc::new(Allocator::new(usize::MAX));
290+
let first_alloc = Rc::new(Allocator::new(usize::MAX, name));
244291
let mut fut = Box::pin(f(first_alloc.clone()));
245292
let mut ops_before_last_poll = 0;
246293
let mut completed = false;
247294
for _ in 0..polls {
248295
ops_before_last_poll = first_alloc.cur_ops.get();
249-
if let Poll::Ready(()) = fut.as_mut().poll(cx) {
296+
if let Poll::Ready(_) = fut.as_mut().poll(cx) {
250297
completed = true;
251298
}
252299
}
@@ -255,7 +302,7 @@ where
255302
// Start at `ops_before_last_poll` so that we will always be able to
256303
// `poll` the expected number of times.
257304
for failing_op in ops_before_last_poll..first_alloc.cur_ops.get() {
258-
let alloc = Rc::new(Allocator::new(failing_op + 1));
305+
let alloc = Rc::new(Allocator::new(failing_op + 1, name));
259306
let f = &f;
260307
let cx = &mut *cx;
261308
let result = panic::catch_unwind(panic::AssertUnwindSafe(move || {
@@ -285,48 +332,58 @@ fn clone_waker(data: *const ()) -> RawWaker {
285332
RawWaker::new(data, &RawWakerVTable::new(clone_waker, drop, drop, drop))
286333
}
287334

335+
macro_rules! run_test {
336+
($ctxt:expr, $e:expr) => { run_test($ctxt, $e, stringify!($e)); };
337+
}
338+
288339
fn main() {
289340
let waker = unsafe { Waker::from_raw(clone_waker(ptr::null())) };
290341
let context = &mut Context::from_waker(&waker);
291342

292-
run_test(context, |a| dynamic_init(a, false));
293-
run_test(context, |a| dynamic_init(a, true));
294-
run_test(context, |a| dynamic_drop(a, false));
295-
run_test(context, |a| dynamic_drop(a, true));
296-
297-
run_test(context, |a| assignment(a, false, false));
298-
run_test(context, |a| assignment(a, false, true));
299-
run_test(context, |a| assignment(a, true, false));
300-
run_test(context, |a| assignment(a, true, true));
301-
302-
run_test(context, |a| array_simple(a));
303-
run_test(context, |a| vec_simple(a));
304-
run_test(context, |a| vec_unreachable(a));
305-
306-
run_test(context, |a| struct_dynamic_drop(a, false, false, false));
307-
run_test(context, |a| struct_dynamic_drop(a, false, false, true));
308-
run_test(context, |a| struct_dynamic_drop(a, false, true, false));
309-
run_test(context, |a| struct_dynamic_drop(a, false, true, true));
310-
run_test(context, |a| struct_dynamic_drop(a, true, false, false));
311-
run_test(context, |a| struct_dynamic_drop(a, true, false, true));
312-
run_test(context, |a| struct_dynamic_drop(a, true, true, false));
313-
run_test(context, |a| struct_dynamic_drop(a, true, true, true));
314-
315-
run_test(context, |a| field_assignment(a, false));
316-
run_test(context, |a| field_assignment(a, true));
317-
318-
run_test(context, |a| mixed_drop_and_nondrop(a));
319-
320-
run_test(context, |a| slice_pattern_one_of(a, 0));
321-
run_test(context, |a| slice_pattern_one_of(a, 1));
322-
run_test(context, |a| slice_pattern_one_of(a, 2));
323-
run_test(context, |a| slice_pattern_one_of(a, 3));
324-
325-
run_test(context, |a| subslice_pattern_from_end_with_drop(a, true, true));
326-
run_test(context, |a| subslice_pattern_from_end_with_drop(a, true, false));
327-
run_test(context, |a| subslice_pattern_from_end_with_drop(a, false, true));
328-
run_test(context, |a| subslice_pattern_from_end_with_drop(a, false, false));
329-
run_test(context, |a| subslice_pattern_reassign(a));
330-
331-
run_test(context, |a| move_ref_pattern(a));
343+
run_test!(context, |a| dynamic_init(a, false));
344+
run_test!(context, |a| dynamic_init(a, true));
345+
run_test!(context, |a| dynamic_drop(a, false));
346+
run_test!(context, |a| dynamic_drop(a, true));
347+
348+
run_test!(context, |a| assignment(a, false, false));
349+
run_test!(context, |a| assignment(a, false, true));
350+
run_test!(context, |a| assignment(a, true, false));
351+
run_test!(context, |a| assignment(a, true, true));
352+
353+
run_test!(context, |a| array_simple(a));
354+
run_test!(context, |a| vec_simple(a));
355+
run_test!(context, |a| vec_unreachable(a));
356+
357+
run_test!(context, |a| struct_dynamic_drop(a, false, false, false));
358+
run_test!(context, |a| struct_dynamic_drop(a, false, false, true));
359+
run_test!(context, |a| struct_dynamic_drop(a, false, true, false));
360+
run_test!(context, |a| struct_dynamic_drop(a, false, true, true));
361+
run_test!(context, |a| struct_dynamic_drop(a, true, false, false));
362+
run_test!(context, |a| struct_dynamic_drop(a, true, false, true));
363+
run_test!(context, |a| struct_dynamic_drop(a, true, true, false));
364+
run_test!(context, |a| struct_dynamic_drop(a, true, true, true));
365+
366+
run_test!(context, |a| field_assignment(a, false));
367+
run_test!(context, |a| field_assignment(a, true));
368+
369+
run_test!(context, |a| mixed_drop_and_nondrop(a));
370+
371+
run_test!(context, |a| slice_pattern_one_of(a, 0));
372+
run_test!(context, |a| slice_pattern_one_of(a, 1));
373+
run_test!(context, |a| slice_pattern_one_of(a, 2));
374+
run_test!(context, |a| slice_pattern_one_of(a, 3));
375+
376+
run_test!(context, |a| subslice_pattern_from_end_with_drop(a, true, true));
377+
run_test!(context, |a| subslice_pattern_from_end_with_drop(a, true, false));
378+
run_test!(context, |a| subslice_pattern_from_end_with_drop(a, false, true));
379+
run_test!(context, |a| subslice_pattern_from_end_with_drop(a, false, false));
380+
run_test!(context, |a| subslice_pattern_reassign(a));
381+
382+
run_test!(context, |a| move_ref_pattern(a));
383+
384+
run_test!(context, |a| panic_after_return(a, false));
385+
run_test!(context, |a| panic_after_return(a, true));
386+
run_test!(context, |a| panic_after_init_by_loop(a));
387+
run_test!(context, |a| panic_after_init_by_match_with_bindings_and_guard(a, false));
388+
run_test!(context, |a| panic_after_init_by_match_with_bindings_and_guard(a, true));
332389
}

‎tests/ui/drop/dynamic-drop.rs

Lines changed: 243 additions & 167 deletions
Large diffs are not rendered by default.

‎tests/ui/nll/ice-106874.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ pub fn func<V, F: Fn(&mut V)>(f: F) -> A<impl X> {
1414
//~| ERROR implementation of `FnOnce` is not general enough
1515
//~| ERROR implementation of `Fn` is not general enough
1616
//~| ERROR implementation of `FnOnce` is not general enough
17-
//~| ERROR higher-ranked subtype error
18-
//~| ERROR higher-ranked subtype error
1917
}
2018

2119
trait X {}

‎tests/ui/nll/ice-106874.stderr

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -72,19 +72,5 @@ LL | A(B(C::new(D::new(move |st| f(st)))))
7272
= note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`...
7373
= note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2`
7474

75-
error: higher-ranked subtype error
76-
--> $DIR/ice-106874.rs:8:41
77-
|
78-
LL | A(B(C::new(D::new(move |st| f(st)))))
79-
| ^
80-
81-
error: higher-ranked subtype error
82-
--> $DIR/ice-106874.rs:8:41
83-
|
84-
LL | A(B(C::new(D::new(move |st| f(st)))))
85-
| ^
86-
|
87-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
88-
89-
error: aborting due to 10 previous errors
75+
error: aborting due to 8 previous errors
9076

0 commit comments

Comments
 (0)
This repository has been archived.