@@ -690,14 +690,20 @@ impl<T> Vec<T> {
690
690
/// [`drain`]: #method.drain
691
691
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
692
692
pub fn truncate ( & mut self , len : usize ) {
693
+ let current_len = self . len ;
693
694
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
+
694
702
// 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) ;
701
707
}
702
708
}
703
709
}
@@ -1512,6 +1518,11 @@ impl<'a> SetLenOnDrop<'a> {
1512
1518
fn increment_len ( & mut self , increment : usize ) {
1513
1519
self . local_len += increment;
1514
1520
}
1521
+
1522
+ #[ inline]
1523
+ fn decrement_len ( & mut self , decrement : usize ) {
1524
+ self . local_len -= decrement;
1525
+ }
1515
1526
}
1516
1527
1517
1528
impl < ' a > Drop for SetLenOnDrop < ' a > {
0 commit comments