If we have code that's structured like this:
fn foo<T>() {
if !std::mem::needs_drop::<T>() { return; }
// More code here, using T.
let mut v = Vec::<T>::with_capacity(1024);
// ...
}
For a given type that exits early from this function, like for example i32
(does not need drop), in what part of compilation and when are the generic items that follow in the foo function pruned?
It seems like, from debug mode compilation, that quite a lot of the code in the dead branch will be instantiated and code-generated, even though it should be unreachable.
Does anyone know more details when in compilation this code is removed? I'd want to avoid that it gets emitted for optimization to llvm, so that the compiler doesn't have to do a lot of extra work - for example optimizing Vec::with_capacity
for a type that's not even going to be used at that point.
I know that if we had a trait for needs_drop
, that it would be possible to statically avoid this extra code generation. Does anyone know other tricks for avoiding problems with this in practice?
The question comes from the the following (more complicated) code (original code is here), that also involves significant code generation with the same needs_drop
conditional.
/// Apply and collect the results into a new array, which has the same size as the
/// inputs.
///
/// If all inputs are c- or f-order respectively, that is preserved in the output.
pub fn apply_collect<R>(self, f: impl FnMut(P1::Item, P2::Item) -> R) -> Array<R, D>
where P1: NdProducer<..>, P2: NdProducer<..>
{
// Make uninit result
let mut output = self.uninitalized_for_current_layout::<R>();
if !std::mem::needs_drop::<R>() {
// For elements with no drop glue, just overwrite into the array
self.apply_assign_into(&mut output, f);
} else {
// For generic elements, use a proxy that counts the number of filled elements,
// and can drop the right number of elements on unwinding
unsafe {
PartialArray::scope(output.view_mut(), move |partial| {
debug_assert_eq!(partial.layout().tendency() >= 0, self.layout_tendency >= 0);
self.apply_assign_into(partial, f);
});
}
}
unsafe {
output.assume_init()
}
}