@@ -690,14 +690,20 @@ impl<T> Vec<T> {
690690 /// [`drain`]: #method.drain
691691 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
692692 pub fn truncate ( & mut self , len : usize ) {
693+ let current_len = self . len ;
693694 unsafe {
695+ let mut ptr = self . as_mut_ptr ( ) . offset ( self . len as isize ) ;
696+ // Set the final length at the end, keeping in mind that
697+ // dropping an element might panic. Works around a missed
698+ // optimization, as seen in the following issue:
699+ // https://github.com/rust-lang/rust/issues/51802
700+ let mut local_len = SetLenOnDrop :: new ( & mut self . len ) ;
701+
694702 // drop any extra elements
695- while len < self . len {
696- // decrement len before the drop_in_place(), so a panic on Drop
697- // doesn't re-drop the just-failed value.
698- self . len -= 1 ;
699- let len = self . len ;
700- ptr:: drop_in_place ( self . get_unchecked_mut ( len) ) ;
703+ for _ in len..current_len {
704+ local_len. decrement_len ( 1 ) ;
705+ ptr = ptr. offset ( -1 ) ;
706+ ptr:: drop_in_place ( ptr) ;
701707 }
702708 }
703709 }
@@ -1512,6 +1518,11 @@ impl<'a> SetLenOnDrop<'a> {
15121518 fn increment_len ( & mut self , increment : usize ) {
15131519 self . local_len += increment;
15141520 }
1521+
1522+ #[ inline]
1523+ fn decrement_len ( & mut self , decrement : usize ) {
1524+ self . local_len -= decrement;
1525+ }
15151526}
15161527
15171528impl < ' a > Drop for SetLenOnDrop < ' a > {
0 commit comments