Code change:
This bug has already been identified but I wanted to open an issue for it. The following code should print first. () I believe there is an unanswered question: Should temporaries be dropped before the block? said this issue is being investigated at <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --This issue has been assigned to via . <!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
assign (I'm pretty sure you are working on this at )
I think they should, since this would be consistent with if/else. ()
Originally reported in: There are also some variations of it: I've made a little test case for it that doesn't rely on printf but instead can be ran as a run-pass test:
I believe the two tests in shall be comparing to . The reason is that actually extends the temporary to the end of the block at the moment, which is the desired outcome. cc
good point. What's important is that both the let-else and let-else free version are doing the same thing. Maybe one can add an additional block around the and then add a second to ensure it dropped after the block terminated? Edit: nvm, it's not possible as the .stdout files are for compiler output, not runtime output of the tests.
<details<summaryHere's another way to test, using Rc</summary</details
It might also be an idea to add a test for the inconsistency between if and if let: (no matter which side of the divide let else is on, make sure that there is no breakage of it in the future)
The above test for "drop before else block" failed on master. Reopening.
Allow me to notify that I am currently looking at how to drop values earlier inside the block.
So I was rebasing onto latest master and I wanted to share this as part of the diff: ! There has been great improvement by but it was no full fix, especially this still post-drops: prints: If you remove the it works now thanks to .
I think this is because the borrowed is assigned with extended lifetime. only breaks out towards the remainder scope. It turns out this is not sufficient. I will try to break out to further one scope up, say the parent remainder scope of the current one. I feel that this should suffice.
This is correct behavior I think. Anything accessible in the pattern needs to be in scope till the end of the block. Consider you can write . It shouldn't depend on whether the pattern matches since that is not known at compile time generally.
yeah it may not be dropped before the code after the construct terminates, but it can be dropped before the block.
I see. I think this is the non-temporary case, when the pattern doesn't match.

Related discussion:
text: initializer_span: Span, else_block: &Block, visibility_scope: Option<SourceScope>, <ins> remainder_scope: region::Scope, </ins> remainder_span: Span, pattern: &Pat<'tcx>, ) -> BlockAnd<()> { <del> let scrutinee = unpack!(block = self.lower_scrutinee(block, init, initializer_span)); let pat = Pat { ty: init.ty, span: else_block.span, kind: Box::new(PatKind::Wild) }; let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false); self.declare_bindings( visibility_scope, remainder_span, pattern, ArmHasGuard(false), Some((None, initializer_span)), ); let mut candidate = Candidate::new(scrutinee.clone(), pattern, false); let fake_borrow_temps = self.lower_match_tree( block, initializer_span, pattern.span, false, &mut [&mut candidate, &mut wildcard], ); // This block is for the matching case let matching = self.bind_pattern( self.source_info(pattern.span), candidate, None, &fake_borrow_temps, initializer_span, None, None, None, ); // This block is for the failure case let failure = self.bind_pattern( self.source_info(else_block.span), wildcard, None, &fake_borrow_temps, initializer_span, None, None, None, ); </del> <ins> let (matching, failure) = self.in_if_then_scope(remainder_scope, |this| { let scrutinee = unpack!(block = this.lower_scrutinee(block, init, initializer_span)); let pat = Pat { ty: init.ty, span: else_block.span, kind: Box::new(PatKind::Wild) }; let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false); this.declare_bindings( visibility_scope, remainder_span, pattern, ArmHasGuard(false), Some((None, initializer_span)), ); let mut candidate = Candidate::new(scrutinee.clone(), pattern, false); let fake_borrow_temps = this.lower_match_tree( block, initializer_span, pattern.span, false, &mut [&mut candidate, &mut wildcard], ); // This block is for the matching case let matching = this.bind_pattern( this.source_info(pattern.span), candidate, None, &fake_borrow_temps, initializer_span, None, None, None, ); // This block is for the failure case let failure = this.bind_pattern( this.source_info(else_block.span), wildcard, None, &fake_borrow_temps, initializer_span, None, None, None, ); this.break_for_else(failure, remainder_scope, this.source_info(initializer_span)); matching.unit() }); </ins> // This place is not really used because this destination place // should never be used to take values at the end of the failure // block.