From add921f8d24413059d55596ee224ac7b3a62e7b3 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 30 Nov 2022 22:24:53 -0800 Subject: [PATCH] Help infer may_dangle on type parameter of Punctuated iterator Drop impls --- src/drops.rs | 58 +++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/punctuated.rs | 47 ++++++++++++++++++++++++++------------ 3 files changed, 91 insertions(+), 15 deletions(-) create mode 100644 src/drops.rs diff --git a/src/drops.rs b/src/drops.rs new file mode 100644 index 0000000000..89b42d82ef --- /dev/null +++ b/src/drops.rs @@ -0,0 +1,58 @@ +use std::iter; +use std::mem::ManuallyDrop; +use std::ops::{Deref, DerefMut}; +use std::option; +use std::slice; + +#[repr(transparent)] +pub(crate) struct NoDrop(ManuallyDrop); + +impl NoDrop { + pub(crate) fn new(value: T) -> Self + where + T: TrivialDrop, + { + NoDrop(ManuallyDrop::new(value)) + } +} + +impl Deref for NoDrop { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for NoDrop { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +pub(crate) trait TrivialDrop {} + +impl TrivialDrop for iter::Empty {} +impl<'a, T> TrivialDrop for slice::Iter<'a, T> {} +impl<'a, T> TrivialDrop for slice::IterMut<'a, T> {} +impl<'a, T> TrivialDrop for option::IntoIter<&'a T> {} +impl<'a, T> TrivialDrop for option::IntoIter<&'a mut T> {} + +#[test] +fn test_needs_drop() { + use std::mem::needs_drop; + + struct NeedsDrop; + + impl Drop for NeedsDrop { + fn drop(&mut self) {} + } + + assert!(needs_drop::()); + + // Test each of the types with a handwritten TrivialDrop impl above. + assert!(!needs_drop::>()); + assert!(!needs_drop::>()); + assert!(!needs_drop::>()); + assert!(!needs_drop::>()); + assert!(!needs_drop::>()); +} diff --git a/src/lib.rs b/src/lib.rs index 7d4df7110c..977140269f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -429,6 +429,7 @@ pub use crate::path::{ #[cfg(feature = "parsing")] #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] pub mod buffer; +mod drops; #[cfg(feature = "parsing")] #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] pub mod ext; diff --git a/src/punctuated.rs b/src/punctuated.rs index 0fe1078cf4..a5b0dbca01 100644 --- a/src/punctuated.rs +++ b/src/punctuated.rs @@ -24,14 +24,13 @@ use std::fmt::{self, Debug}; #[cfg(feature = "extra-traits")] use std::hash::{Hash, Hasher}; -#[cfg(any(feature = "full", feature = "derive"))] -use std::iter; -use std::iter::FromIterator; +use std::iter::{self, FromIterator}; use std::ops::{Index, IndexMut}; use std::option; use std::slice; use std::vec; +use crate::drops::{NoDrop, TrivialDrop}; #[cfg(feature = "parsing")] use crate::parse::{Parse, ParseStream, Result}; #[cfg(feature = "parsing")] @@ -104,10 +103,10 @@ impl Punctuated { /// Returns an iterator over borrowed syntax tree nodes of type `&T`. pub fn iter(&self) -> Iter { Iter { - inner: Box::new(PrivateIter { + inner: Box::new(NoDrop::new(PrivateIter { inner: self.inner.iter(), last: self.last.as_ref().map(Box::as_ref).into_iter(), - }), + })), } } @@ -115,10 +114,10 @@ impl Punctuated { /// `&mut T`. pub fn iter_mut(&mut self) -> IterMut { IterMut { - inner: Box::new(PrivateIterMut { + inner: Box::new(NoDrop::new(PrivateIterMut { inner: self.inner.iter_mut(), last: self.last.as_mut().map(Box::as_mut).into_iter(), - }), + })), } } @@ -721,13 +720,13 @@ pub struct Iter<'a, T: 'a> { // The `Item = &'a T` needs to be specified to support rustc 1.31 and older. // On modern compilers we would be able to write just IterTrait<'a, T> where // Item can be inferred unambiguously from the supertrait. - inner: Box + 'a>, + inner: Box + 'a>>, } trait IterTrait<'a, T: 'a>: DoubleEndedIterator + ExactSizeIterator { - fn clone_box(&self) -> Box + 'a>; + fn clone_box(&self) -> Box + 'a>>; } struct PrivateIter<'a, T: 'a, P: 'a> { @@ -735,10 +734,17 @@ struct PrivateIter<'a, T: 'a, P: 'a> { last: option::IntoIter<&'a T>, } +impl<'a, T, P> TrivialDrop for PrivateIter<'a, T, P> +where + slice::Iter<'a, (T, P)>: TrivialDrop, + option::IntoIter<&'a T>: TrivialDrop, +{ +} + #[cfg(any(feature = "full", feature = "derive"))] pub(crate) fn empty_punctuated_iter<'a, T>() -> Iter<'a, T> { Iter { - inner: Box::new(iter::empty()), + inner: Box::new(NoDrop::new(iter::empty())), } } @@ -813,10 +819,14 @@ impl<'a, T, P> Clone for PrivateIter<'a, T, P> { impl<'a, T, I> IterTrait<'a, T> for I where T: 'a, - I: DoubleEndedIterator + ExactSizeIterator + Clone + 'a, + I: DoubleEndedIterator + + ExactSizeIterator + + Clone + + TrivialDrop + + 'a, { - fn clone_box(&self) -> Box + 'a> { - Box::new(self.clone()) + fn clone_box(&self) -> Box + 'a>> { + Box::new(NoDrop::new(self.clone())) } } @@ -826,7 +836,7 @@ where /// /// [module documentation]: self pub struct IterMut<'a, T: 'a> { - inner: Box + 'a>, + inner: Box + 'a>>, } trait IterMutTrait<'a, T: 'a>: @@ -839,10 +849,17 @@ struct PrivateIterMut<'a, T: 'a, P: 'a> { last: option::IntoIter<&'a mut T>, } +impl<'a, T, P> TrivialDrop for PrivateIterMut<'a, T, P> +where + slice::IterMut<'a, (T, P)>: TrivialDrop, + option::IntoIter<&'a mut T>: TrivialDrop, +{ +} + #[cfg(any(feature = "full", feature = "derive"))] pub(crate) fn empty_punctuated_iter_mut<'a, T>() -> IterMut<'a, T> { IterMut { - inner: Box::new(iter::empty()), + inner: Box::new(NoDrop::new(iter::empty())), } }