diff --git a/components/servo_arc/lib.rs b/components/servo_arc/lib.rs index 780f7485eb9..3cc2b0e7fcc 100644 --- a/components/servo_arc/lib.rs +++ b/components/servo_arc/lib.rs @@ -168,7 +168,7 @@ impl Arc { pub fn new(data: T) -> Self { let x = Box::new(ArcInner { count: atomic::AtomicUsize::new(1), - data: data, + data, }); unsafe { Arc { @@ -610,7 +610,7 @@ impl Arc> { let size = { // First, determine the alignment of a hypothetical pointer to a // HeaderSlice. - let fake_slice_ptr_align: usize = mem::align_of::>>(); + let fake_slice_ptr_align: usize = mem::align_of::>>(); // Next, synthesize a totally garbage (but properly aligned) pointer // to a sequence of T. @@ -667,23 +667,24 @@ impl Arc> { }; ptr::write(&mut ((*ptr).count), count); ptr::write(&mut ((*ptr).data.header), header); - let mut current: *mut T = &mut (*ptr).data.slice[0]; - for _ in 0..num_items { - ptr::write( - current, - items - .next() - .expect("ExactSizeIterator over-reported length"), - ); - current = current.offset(1); + if num_items != 0 { + let mut current: *mut T = &mut (*ptr).data.slice[0]; + for _ in 0..num_items { + ptr::write( + current, + items + .next() + .expect("ExactSizeIterator over-reported length"), + ); + current = current.offset(1); + } + // We should have consumed the buffer exactly. + debug_assert_eq!(current as *mut u8, buffer.offset(size as isize)); } assert!( items.next().is_none(), "ExactSizeIterator under-reported length" ); - - // We should have consumed the buffer exactly. - debug_assert_eq!(current as *mut u8, buffer.offset(size as isize)); } // Return the fat Arc. @@ -772,11 +773,13 @@ type HeaderSliceWithLength = HeaderSlice, T>; /// have a thin pointer instead, perhaps for FFI compatibility /// or space efficiency. /// +/// Note that we use `[T; 0]` in order to have the right alignment for `T`. +/// /// `ThinArc` solves this by storing the length in the allocation itself, /// via `HeaderSliceWithLength`. #[repr(C)] pub struct ThinArc { - ptr: ptr::NonNull>>, + ptr: ptr::NonNull>>, phantom: PhantomData<(H, T)>, } @@ -787,7 +790,7 @@ unsafe impl Sync for ThinArc {} // // See the comment around the analogous operation in from_header_and_iter. fn thin_to_thick( - thin: *mut ArcInner>, + thin: *mut ArcInner>, ) -> *mut ArcInner> { let len = unsafe { (*thin).data.header.length }; let fake_slice: *mut [T] = unsafe { slice::from_raw_parts_mut(thin as *mut T, len) }; @@ -905,7 +908,7 @@ impl Arc> { let thin_ptr = fat_ptr as *mut [usize] as *mut usize; ThinArc { ptr: unsafe { - ptr::NonNull::new_unchecked(thin_ptr as *mut ArcInner>) + ptr::NonNull::new_unchecked(thin_ptr as *mut ArcInner>) }, phantom: PhantomData, } @@ -1320,6 +1323,17 @@ mod tests { } } + #[test] + fn empty_thin() { + let header = HeaderWithLength::new(100u32, 0); + let x = Arc::from_header_and_iter(header, std::iter::empty::()); + let y = Arc::into_thin(x.clone()); + assert_eq!(y.header.header, 100); + assert!(y.slice.is_empty()); + assert_eq!(x.header.header, 100); + assert!(x.slice.is_empty()); + } + #[test] fn slices_and_thin() { let mut canary = atomic::AtomicUsize::new(0);