Skip to content

Commit

Permalink
generator: Work around invariance for assigning mutable pointer of li…
Browse files Browse the repository at this point in the history
…fetimed slice (#841)

In essence this builder function needs to adhere to two rules:
1. No ref-after-free: the slice must outlive (uses of) the builder
   object;
2. No aliasing: the slice cannot be (im)mutably used while it is mutably
   borrowed within a live builder object.

These two rules have been tested and are satisfied by the given builder
implementation.  Without this change `timings` seems to be borrowing
itself, hence is not allowed to be used after it has been temporarily
mutably borrowed inside the builder, even after that builder was
dropped.  Thus defeating the purpose of this "getter" API via a struct.

Without the `.cast()`, because mutable raw pointers are invariant
(i.e. there is no subtyping relationship) the compiler complains about
requiring `self` to outlive `timings` instead, which does not satisfy
the two rules above.
  • Loading branch information
MarijnS95 authored Dec 2, 2023
1 parent 4e99de1 commit e5b0873
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 5 deletions.
4 changes: 2 additions & 2 deletions ash/src/vk/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52045,9 +52045,9 @@ unsafe impl<'a> TaggedStructure for GetLatencyMarkerInfoNV<'a> {
}
impl<'a> GetLatencyMarkerInfoNV<'a> {
#[inline]
pub fn timings(mut self, timings: &'a mut [LatencyTimingsFrameReportNV<'a>]) -> Self {
pub fn timings(mut self, timings: &'a mut [LatencyTimingsFrameReportNV<'_>]) -> Self {
self.timing_count = timings.len() as _;
self.p_timings = timings.as_mut_ptr();
self.p_timings = timings.as_mut_ptr().cast();
self
}
}
Expand Down
12 changes: 9 additions & 3 deletions generator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1929,7 +1929,7 @@ fn derive_setters(

let deprecated = member.deprecated.as_ref().map(|d| quote!(#d #[allow(deprecated)]));
let param_ident = field.param_ident();
let type_lifetime = has_lifetimes
let mut type_lifetime = has_lifetimes
.contains(&name_to_tokens(&field.basetype))
.then(|| quote!(<'a>));
let param_ty_tokens = field.safe_type_tokens(quote!('a), type_lifetime.clone(), None);
Expand Down Expand Up @@ -2018,14 +2018,20 @@ fn derive_setters(
// TODO: Improve in future when https://github.com/rust-lang/rust/issues/53667 is merged id:6
if field.reference.is_some() && matches!(field.array, Some(vkxml::ArrayType::Dynamic)) {
if let Some(ref array_size) = field.size {
let mut slice_param_ty_tokens = field.safe_type_tokens(quote!('a), type_lifetime.clone(), None);

let mut ptr = if field.is_const {
quote!(.as_ptr())
} else if let Some(tl) = &mut type_lifetime {
// Work around invariance with mutable pointers:
// https://github.com/ash-rs/ash/issues/837
// https://doc.rust-lang.org/nomicon/subtyping.html#variance
*tl = quote!(<'_>);
quote!(.as_mut_ptr().cast())
} else {
quote!(.as_mut_ptr())
};

let mut slice_param_ty_tokens = field.safe_type_tokens(quote!('a), type_lifetime.clone(), None);

// Interpret void array as byte array
if field.basetype == "void" && matches!(field.reference, Some(vkxml::ReferenceType::Pointer)) {
slice_param_ty_tokens = quote!([u8]);
Expand Down

0 comments on commit e5b0873

Please sign in to comment.