From e5b08732db837d6205d11de4f09a27aea83d085f Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Sat, 2 Dec 2023 19:52:35 +0100 Subject: [PATCH] generator: Work around invariance for assigning mutable pointer of lifetimed 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. --- ash/src/vk/definitions.rs | 4 ++-- generator/src/lib.rs | 12 +++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/ash/src/vk/definitions.rs b/ash/src/vk/definitions.rs index c0b537d..dcc9d86 100644 --- a/ash/src/vk/definitions.rs +++ b/ash/src/vk/definitions.rs @@ -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 } } diff --git a/generator/src/lib.rs b/generator/src/lib.rs index 806c974..2b27ed6 100644 --- a/generator/src/lib.rs +++ b/generator/src/lib.rs @@ -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); @@ -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]);