Skip to content

Commit 02e2a21

Browse files
authored
Merge pull request #1247 from dtolnay/punctdrop
Infer may_dangle on type parameters of Punctuated iterator Drop impls
2 parents 17f9a5c + 9113ad0 commit 02e2a21

File tree

4 files changed

+109
-12
lines changed

4 files changed

+109
-12
lines changed

src/drops.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use std::iter;
2+
use std::mem::ManuallyDrop;
3+
use std::ops::{Deref, DerefMut};
4+
use std::option;
5+
use std::slice;
6+
7+
#[repr(transparent)]
8+
pub(crate) struct NoDrop<T: ?Sized>(ManuallyDrop<T>);
9+
10+
impl<T> NoDrop<T> {
11+
pub(crate) fn new(value: T) -> Self
12+
where
13+
T: TrivialDrop,
14+
{
15+
NoDrop(ManuallyDrop::new(value))
16+
}
17+
}
18+
19+
impl<T: ?Sized> Deref for NoDrop<T> {
20+
type Target = T;
21+
fn deref(&self) -> &Self::Target {
22+
&self.0
23+
}
24+
}
25+
26+
impl<T: ?Sized> DerefMut for NoDrop<T> {
27+
fn deref_mut(&mut self) -> &mut Self::Target {
28+
&mut self.0
29+
}
30+
}
31+
32+
pub(crate) trait TrivialDrop {}
33+
34+
impl<T> TrivialDrop for iter::Empty<T> {}
35+
impl<'a, T> TrivialDrop for slice::Iter<'a, T> {}
36+
impl<'a, T> TrivialDrop for slice::IterMut<'a, T> {}
37+
impl<'a, T> TrivialDrop for option::IntoIter<&'a T> {}
38+
impl<'a, T> TrivialDrop for option::IntoIter<&'a mut T> {}
39+
40+
#[test]
41+
fn test_needs_drop() {
42+
use std::mem::needs_drop;
43+
44+
struct NeedsDrop;
45+
46+
impl Drop for NeedsDrop {
47+
fn drop(&mut self) {}
48+
}
49+
50+
assert!(needs_drop::<NeedsDrop>());
51+
52+
// Test each of the types with a handwritten TrivialDrop impl above.
53+
assert!(!needs_drop::<iter::Empty<NeedsDrop>>());
54+
assert!(!needs_drop::<slice::Iter<NeedsDrop>>());
55+
assert!(!needs_drop::<slice::IterMut<NeedsDrop>>());
56+
assert!(!needs_drop::<option::IntoIter<&NeedsDrop>>());
57+
assert!(!needs_drop::<option::IntoIter<&mut NeedsDrop>>());
58+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ pub use crate::path::{
429429
#[cfg(feature = "parsing")]
430430
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
431431
pub mod buffer;
432+
mod drops;
432433
#[cfg(feature = "parsing")]
433434
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
434435
pub mod ext;

src/punctuated.rs

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use std::option;
3232
use std::slice;
3333
use std::vec;
3434

35+
use crate::drops::{NoDrop, TrivialDrop};
3536
#[cfg(feature = "parsing")]
3637
use crate::parse::{Parse, ParseStream, Result};
3738
#[cfg(feature = "parsing")]
@@ -104,21 +105,21 @@ impl<T, P> Punctuated<T, P> {
104105
/// Returns an iterator over borrowed syntax tree nodes of type `&T`.
105106
pub fn iter(&self) -> Iter<T> {
106107
Iter {
107-
inner: Box::new(PrivateIter {
108+
inner: Box::new(NoDrop::new(PrivateIter {
108109
inner: self.inner.iter(),
109110
last: self.last.as_ref().map(Box::as_ref).into_iter(),
110-
}),
111+
})),
111112
}
112113
}
113114

114115
/// Returns an iterator over mutably borrowed syntax tree nodes of type
115116
/// `&mut T`.
116117
pub fn iter_mut(&mut self) -> IterMut<T> {
117118
IterMut {
118-
inner: Box::new(PrivateIterMut {
119+
inner: Box::new(NoDrop::new(PrivateIterMut {
119120
inner: self.inner.iter_mut(),
120121
last: self.last.as_mut().map(Box::as_mut).into_iter(),
121-
}),
122+
})),
122123
}
123124
}
124125

@@ -721,24 +722,31 @@ pub struct Iter<'a, T: 'a> {
721722
// The `Item = &'a T` needs to be specified to support rustc 1.31 and older.
722723
// On modern compilers we would be able to write just IterTrait<'a, T> where
723724
// Item can be inferred unambiguously from the supertrait.
724-
inner: Box<dyn IterTrait<'a, T, Item = &'a T> + 'a>,
725+
inner: Box<NoDrop<dyn IterTrait<'a, T, Item = &'a T> + 'a>>,
725726
}
726727

727728
trait IterTrait<'a, T: 'a>:
728729
DoubleEndedIterator<Item = &'a T> + ExactSizeIterator<Item = &'a T>
729730
{
730-
fn clone_box(&self) -> Box<dyn IterTrait<'a, T, Item = &'a T> + 'a>;
731+
fn clone_box(&self) -> Box<NoDrop<dyn IterTrait<'a, T, Item = &'a T> + 'a>>;
731732
}
732733

733734
struct PrivateIter<'a, T: 'a, P: 'a> {
734735
inner: slice::Iter<'a, (T, P)>,
735736
last: option::IntoIter<&'a T>,
736737
}
737738

739+
impl<'a, T, P> TrivialDrop for PrivateIter<'a, T, P>
740+
where
741+
slice::Iter<'a, (T, P)>: TrivialDrop,
742+
option::IntoIter<&'a T>: TrivialDrop,
743+
{
744+
}
745+
738746
#[cfg(any(feature = "full", feature = "derive"))]
739747
pub(crate) fn empty_punctuated_iter<'a, T>() -> Iter<'a, T> {
740748
Iter {
741-
inner: Box::new(iter::empty()),
749+
inner: Box::new(NoDrop::new(iter::empty())),
742750
}
743751
}
744752

@@ -813,10 +821,14 @@ impl<'a, T, P> Clone for PrivateIter<'a, T, P> {
813821
impl<'a, T, I> IterTrait<'a, T> for I
814822
where
815823
T: 'a,
816-
I: DoubleEndedIterator<Item = &'a T> + ExactSizeIterator<Item = &'a T> + Clone + 'a,
824+
I: DoubleEndedIterator<Item = &'a T>
825+
+ ExactSizeIterator<Item = &'a T>
826+
+ Clone
827+
+ TrivialDrop
828+
+ 'a,
817829
{
818-
fn clone_box(&self) -> Box<dyn IterTrait<'a, T, Item = &'a T> + 'a> {
819-
Box::new(self.clone())
830+
fn clone_box(&self) -> Box<NoDrop<dyn IterTrait<'a, T, Item = &'a T> + 'a>> {
831+
Box::new(NoDrop::new(self.clone()))
820832
}
821833
}
822834

@@ -826,7 +838,7 @@ where
826838
///
827839
/// [module documentation]: self
828840
pub struct IterMut<'a, T: 'a> {
829-
inner: Box<dyn IterMutTrait<'a, T, Item = &'a mut T> + 'a>,
841+
inner: Box<NoDrop<dyn IterMutTrait<'a, T, Item = &'a mut T> + 'a>>,
830842
}
831843

832844
trait IterMutTrait<'a, T: 'a>:
@@ -839,10 +851,17 @@ struct PrivateIterMut<'a, T: 'a, P: 'a> {
839851
last: option::IntoIter<&'a mut T>,
840852
}
841853

854+
impl<'a, T, P> TrivialDrop for PrivateIterMut<'a, T, P>
855+
where
856+
slice::IterMut<'a, (T, P)>: TrivialDrop,
857+
option::IntoIter<&'a mut T>: TrivialDrop,
858+
{
859+
}
860+
842861
#[cfg(any(feature = "full", feature = "derive"))]
843862
pub(crate) fn empty_punctuated_iter_mut<'a, T>() -> IterMut<'a, T> {
844863
IterMut {
845-
inner: Box::new(iter::empty()),
864+
inner: Box::new(NoDrop::new(iter::empty())),
846865
}
847866
}
848867

tests/test_iterators.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,22 @@ fn iter() {
4747
assert_eq!(p.iter_mut().next_back(), Some(&mut 4));
4848
assert_eq!(p.into_iter().next_back(), Some(4));
4949
}
50+
51+
#[test]
52+
fn may_dangle() {
53+
let p: Punctuated<_, Token![,]> = punctuated!(2, 3, 4);
54+
for element in &p {
55+
if *element == 2 {
56+
drop(p);
57+
break;
58+
}
59+
}
60+
61+
let mut p: Punctuated<_, Token![,]> = punctuated!(2, 3, 4);
62+
for element in &mut p {
63+
if *element == 2 {
64+
drop(p);
65+
break;
66+
}
67+
}
68+
}

0 commit comments

Comments
 (0)