Change:
recently started ICEing: So we have a ScalarPair value with Scalar layout. Clearly something went wrong somewhere earlier when that value was constructed. <details<summaryBacktrace</summary</detailsGood commit: ICE:
ICE: Is that a typo? Seems like the first commit you mentioned is more likely to be the cause for this.
is the first bad commit.
The ICE happens while popping a stack frame, here in the interpreter: Specifically this is while returning from . The call site is here in the btree code: That function is really odd since it uses with a non-ZST allocator even if is a ZST! Various parts of rustc cannot yet deal with non-ZST allocators so this is a problem. I wonder if there is any reason that this uses ? AFAIK everywhere else uses to ensure this is zero-cost when is a zero-sized type.
(IOW, this is an instance of , but usually that bug can only be triggered by actually using a custom allocator -- whereas now with this btree implementation it can be triggered even on code not using any unstable features.)
The reason for the is because BTreeMap holds the allocator within its top level struct, but needs to use the same allocator to allocate nodes through , the other option here would be to require the to be so we can call which seems overly restrictive unless we require every to be clone.
is my proposal for fixing this.
If someone has an A: Allocator that is not Copy, they can use &A to get a Copy allocator and pay the cost of the indirection. But your current approach forces everyone to pay that cost, even if their allocator is Copy. That is in violation of the zero cost principle.
Even after landing and , I am still getting ICEs when running the liballoc test suite in Miri -- not entirely sure where they are coming from.
After removing some more from , the ICEs seem gone. :)

Discussion:
&mut self, ) -> Option<Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV>> { if self.length == 0 { <del> self.range.deallocating_end(&self.alloc); </del> <ins> self.range.deallocating_end(self.alloc.clone()); </ins> None } else { self.length -= 1; <del> Some(unsafe { self.range.deallocating_next_unchecked(&self.alloc) }) </del> <ins> Some(unsafe { self.range.deallocating_next_unchecked(self.alloc.clone()) }) </ins> } }

&mut self, ) -> Option<Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV>> { if self.length == 0 { <del> self.range.deallocating_end(&self.alloc); </del> <ins> self.range.deallocating_end(self.alloc.clone()); </ins> None } else { self.length -= 1; <del> Some(unsafe { self.range.deallocating_next_back_unchecked(&self.alloc) }) </del> <ins> Some(unsafe { self.range.deallocating_next_back_unchecked(self.alloc.clone()) }) </ins> } } }

type Item = (K, V); fn next(&mut self) -> Option<(K, V)> { <del> self.inner.next(&mut self.pred, &self.alloc) </del> <ins> self.inner.next(&mut self.pred, self.alloc.clone()) </ins> } fn size_hint(&self) -> (usize, Option<usize>) {

fn next(&mut self) -> Option<T> { let pred = &mut self.pred; let mut mapped_pred = |k: &T, _v: &mut ()| pred(k); <del> self.inner.next(&mut mapped_pred, &self.alloc).map(|(k, _)| k) </del> <ins> self.inner.next(&mut mapped_pred, self.alloc.clone()).map(|(k, _)| k) </ins> } fn size_hint(&self) -> (usize, Option<usize>) {

old_size => unsafe { let new_ptr = self.alloc_impl(new_layout, zeroed)?; ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_size); <del> Allocator::deallocate(&self, ptr, old_layout); </del> <ins> Allocator::deallocate(self, ptr, old_layout); </ins> Ok(new_ptr) }, }

match new_layout.size() { // SAFETY: conditions must be upheld by the caller 0 => unsafe { <del> Allocator::deallocate(&self, ptr, old_layout); </del> <ins> Allocator::deallocate(self, ptr, old_layout); </ins> Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0)) },

// `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract // for `dealloc` must be upheld by the caller. new_size => unsafe { <del> let new_ptr = Allocator::allocate(&self, new_layout)?; </del> <ins> let new_ptr = Allocator::allocate(self, new_layout)?; </ins> ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_size); <del> Allocator::deallocate(&self, ptr, old_layout); </del> <ins> Allocator::deallocate(self, ptr, old_layout); </ins> Ok(new_ptr) }, }