From 13b2af894152156ab04a4092cf1bc03ba7949ca5 Mon Sep 17 00:00:00 2001 From: joshua-maros <60271685+joshua-maros@users.noreply.github.com> Date: Sat, 13 May 2023 23:15:05 -0700 Subject: [PATCH 1/8] Revert "This also does not work" This reverts commit 3e269a742b860251900cd175eece7c54184c16d0. --- examples/src/ok_tests.rs | 10 +++++++ ouroboros_macro/src/generate/into_heads.rs | 31 +++++++++++++++++++--- ouroboros_macro/src/lib.rs | 12 ++++----- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/examples/src/ok_tests.rs b/examples/src/ok_tests.rs index 48a81b1..61ae346 100644 --- a/examples/src/ok_tests.rs +++ b/examples/src/ok_tests.rs @@ -179,6 +179,16 @@ fn try_new_recover_heads() { } } +#[test] +fn into_heads() { + let bar = BoxAndRefBuilder { + data: 12, + dref_builder: |data| data, + } + .build(); + assert!(bar.into_heads().data == 12); +} + #[test] fn box_and_mut_ref() { let mut bar = BoxAndMutRefBuilder { diff --git a/ouroboros_macro/src/generate/into_heads.rs b/ouroboros_macro/src/generate/into_heads.rs index 7b4b122..5784e46 100644 --- a/ouroboros_macro/src/generate/into_heads.rs +++ b/ouroboros_macro/src/generate/into_heads.rs @@ -3,8 +3,8 @@ use quote::quote; use crate::info_structures::{Options, StructInfo}; -/// Returns the Heads struct. -pub fn make_heads(info: &StructInfo, options: Options) -> TokenStream { +/// Returns the Heads struct and a function to convert the original struct into a Heads instance. +pub fn make_into_heads(info: &StructInfo, options: Options) -> (TokenStream, TokenStream) { let visibility = if options.do_pub_extras { info.vis.clone() } else { @@ -51,6 +51,31 @@ pub fn make_heads(info: &StructInfo, options: Options) -> TokenStream { #(#head_fields),* } }; + let documentation = concat!( + "This function drops all internally referencing fields and returns only the ", + "[head fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions) of this struct." + ).to_owned(); - heads_struct_def + let documentation = if !options.do_no_doc { + quote! { + #[doc=#documentation] + } + } else { + quote! { #[doc(hidden)] } + }; + + let generic_args = info.generic_arguments(); + let into_heads_fn = quote! { + #documentation + #[allow(clippy::drop_ref)] + #[allow(clippy::drop_copy)] + #[allow(clippy::drop_non_drop)] + #visibility fn into_heads(self) -> Heads<#(#generic_args),*> { + #(#code)* + Heads { + #(#field_initializers),* + } + } + }; + (heads_struct_def, into_heads_fn) } diff --git a/ouroboros_macro/src/lib.rs b/ouroboros_macro/src/lib.rs index f531fb5..cd12419 100644 --- a/ouroboros_macro/src/lib.rs +++ b/ouroboros_macro/src/lib.rs @@ -9,7 +9,7 @@ mod utils; use crate::{ generate::{ constructor::create_builder_and_constructor, derives::create_derives, - into_heads::make_heads, struc::create_actual_struct_def, + into_heads::make_into_heads, struc::create_actual_struct_def, summon_checker::generate_checker_summoner, try_constructor::create_try_builder_and_constructor, type_asserts::make_type_asserts, with_all::make_with_all_function, with_each::make_with_functions, @@ -50,15 +50,12 @@ fn self_referencing_impl( create_try_builder_and_constructor(&info, options, BuilderType::Sync)?; let (async_try_builder_struct_name, async_try_builder_def, async_try_constructor_def) = create_try_builder_and_constructor(&info, options, BuilderType::Async)?; - let ( - async_send_try_builder_struct_name, - async_send_try_builder_def, - async_send_try_constructor_def, - ) = create_try_builder_and_constructor(&info, options, BuilderType::AsyncSend)?; + let (async_send_try_builder_struct_name, async_send_try_builder_def, async_send_try_constructor_def) = + create_try_builder_and_constructor(&info, options, BuilderType::AsyncSend)?; let with_defs = make_with_functions(&info, options)?; let (with_all_struct_defs, with_all_fn_defs) = make_with_all_function(&info, options)?; - let heads_struct_def = make_heads(&info, options); + let (heads_struct_def, into_heads_fn) = make_into_heads(&info, options); let impls = create_derives(&info)?; @@ -100,6 +97,7 @@ fn self_referencing_impl( #async_send_try_constructor_def #(#with_defs)* #with_all_fn_defs + #into_heads_fn } #type_asserts_def } From c8891142dd2eb437f0dcf2c0ad170be6fbb73d9d Mon Sep 17 00:00:00 2001 From: joshua-maros <60271685+joshua-maros@users.noreply.github.com> Date: Sat, 13 May 2023 23:15:11 -0700 Subject: [PATCH 2/8] Revert "Revert "Failed attempt to fix problems."" This reverts commit b4d49cd874cfc74a3e6c496c61eaacf599330fa0. --- examples/Cargo.toml | 4 +-- examples/src/ok_tests.rs | 3 ++ ouroboros/Cargo.toml | 5 +-- ouroboros/src/lib.rs | 1 + ouroboros_macro/Cargo.toml | 2 +- ouroboros_macro/src/generate/constructor.rs | 15 +++++++-- ouroboros_macro/src/generate/into_heads.rs | 14 +++++---- ouroboros_macro/src/generate/struc.rs | 31 ++++++++++++++++--- .../src/generate/try_constructor.rs | 5 ++- ouroboros_macro/src/generate/with_all.rs | 10 ++++-- ouroboros_macro/src/generate/with_each.rs | 17 +++++++--- ouroboros_macro/src/info_structures.rs | 11 +++++++ ouroboros_macro/src/lib.rs | 5 ++- ouroboros_macro/src/parse.rs | 1 + 14 files changed, 97 insertions(+), 27 deletions(-) diff --git a/examples/Cargo.toml b/examples/Cargo.toml index e8fa0fd..8243ddf 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ouroboros_examples" -version = "0.15.7" +version = "0.16.0" authors = ["Joshua Maros "] edition = "2018" license = "MIT OR Apache-2.0" @@ -21,7 +21,7 @@ std = [] __tokio = ["tokio", "std"] [dependencies] -ouroboros = { version = "0.15.7", path = "../ouroboros" } +ouroboros = { version = "0.16.0", path = "../ouroboros" } tokio = { version = "1.27.0", features = [ "macros", "rt" ], optional = true } [dev-dependencies] diff --git a/examples/src/ok_tests.rs b/examples/src/ok_tests.rs index 61ae346..db27303 100644 --- a/examples/src/ok_tests.rs +++ b/examples/src/ok_tests.rs @@ -1,6 +1,9 @@ use alloc::borrow::ToOwned; use alloc::boxed::Box; +use alloc::vec; +use alloc::vec::Vec; use core::fmt::Debug; +use ouroboros::macro_help::AliasableBox; use ouroboros::self_referencing; diff --git a/ouroboros/Cargo.toml b/ouroboros/Cargo.toml index 4ee1ca3..3c256b4 100644 --- a/ouroboros/Cargo.toml +++ b/ouroboros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ouroboros" -version = "0.15.7" +version = "0.16.0" authors = ["Joshua Maros "] edition = "2018" license = "MIT OR Apache-2.0" @@ -11,7 +11,8 @@ repository = "https://github.com/joshua-maros/ouroboros" [dependencies] aliasable = "0.1.3" -ouroboros_macro = { version = "0.15.7", path = "../ouroboros_macro" } +ouroboros_macro = { version = "0.16.0", path = "../ouroboros_macro" } +static_assertions = "1.1.0" [features] default = ["std"] diff --git a/ouroboros/src/lib.rs b/ouroboros/src/lib.rs index efd32e8..13870da 100644 --- a/ouroboros/src/lib.rs +++ b/ouroboros/src/lib.rs @@ -351,6 +351,7 @@ pub mod macro_help { pub extern crate alloc; pub use aliasable::boxed::AliasableBox; + pub use static_assertions::const_assert_eq; use aliasable::boxed::UniqueBox; pub struct CheckIfTypeIsStd(core::marker::PhantomData); diff --git a/ouroboros_macro/Cargo.toml b/ouroboros_macro/Cargo.toml index a350e81..5b2a56b 100644 --- a/ouroboros_macro/Cargo.toml +++ b/ouroboros_macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ouroboros_macro" -version = "0.15.7" +version = "0.16.0" authors = ["Joshua Maros "] edition = "2018" license = "MIT OR Apache-2.0" diff --git a/ouroboros_macro/src/generate/constructor.rs b/ouroboros_macro/src/generate/constructor.rs index 6ab47bc..2ece184 100644 --- a/ouroboros_macro/src/generate/constructor.rs +++ b/ouroboros_macro/src/generate/constructor.rs @@ -154,12 +154,23 @@ pub fn create_builder_and_constructor( BuilderType::Sync => quote! { fn new }, }; let field_names: Vec<_> = info.fields.iter().map(|field| field.name.clone()).collect(); + let internal_ident = &info.internal_ident; let constructor_def = quote! { #documentation #vis #constructor_fn(#(#params),*) -> #struct_name <#(#generic_args),*> { + ::ouroboros::macro_help::const_assert_eq!( + ::core::mem::size_of::<#struct_name<#(#generic_args),*>>(), + ::core::mem::size_of::<#internal_ident<#(#generic_args),*>>() + ); + ::ouroboros::macro_help::const_assert_eq!( + ::core::mem::align_of::<#struct_name<#(#generic_args),*>>(), + ::core::mem::align_of::<#internal_ident<#(#generic_args),*>>() + ); #(#code)* - Self { - #(#field_names),* + unsafe { + ::core::mem::transmute(#internal_ident<#(#generic_args),*> { + #(#field_names),* + }) } } }; diff --git a/ouroboros_macro/src/generate/into_heads.rs b/ouroboros_macro/src/generate/into_heads.rs index 5784e46..12016a8 100644 --- a/ouroboros_macro/src/generate/into_heads.rs +++ b/ouroboros_macro/src/generate/into_heads.rs @@ -1,5 +1,5 @@ use proc_macro2::TokenStream; -use quote::quote; +use quote::{format_ident, quote}; use crate::info_structures::{Options, StructInfo}; @@ -13,12 +13,16 @@ pub fn make_into_heads(info: &StructInfo, options: Options) -> (TokenStream, Tok let mut code = Vec::new(); let mut field_initializers = Vec::new(); let mut head_fields = Vec::new(); + let internal_struct = &info.internal_ident; // Drop everything in the reverse order of what it was declared in. Fields that come later // are only dependent on fields that came before them. for field in info.fields.iter().rev() { let field_name = &field.name; - if !field.self_referencing { - code.push(quote! { let #field_name = self.#field_name; }); + if field.self_referencing { + // Heads are fields that do not borrow anything. + code.push(quote! { ::core::mem::drop(this.#field_name); }); + } else { + code.push(quote! { let #field_name = this.#field_name; }); if field.is_borrowed() { field_initializers .push(quote! { #field_name: ::ouroboros::macro_help::unbox(#field_name) }); @@ -27,9 +31,6 @@ pub fn make_into_heads(info: &StructInfo, options: Options) -> (TokenStream, Tok } let field_type = &field.typ; head_fields.push(quote! { #visibility #field_name: #field_type }); - } else { - // Heads are fields that do not borrow anything. - code.push(quote! { ::core::mem::drop(self.#field_name); }); } } for (ty, ident) in info.generic_consumers() { @@ -71,6 +72,7 @@ pub fn make_into_heads(info: &StructInfo, options: Options) -> (TokenStream, Tok #[allow(clippy::drop_copy)] #[allow(clippy::drop_non_drop)] #visibility fn into_heads(self) -> Heads<#(#generic_args),*> { + let this: #internal_struct<#(#generic_args),*> = unsafe { ::core::mem::transmute(self) }; #(#code)* Heads { #(#field_initializers),* diff --git a/ouroboros_macro/src/generate/struc.rs b/ouroboros_macro/src/generate/struc.rs index 9b2ff51..8a7b9f4 100644 --- a/ouroboros_macro/src/generate/struc.rs +++ b/ouroboros_macro/src/generate/struc.rs @@ -6,12 +6,35 @@ use proc_macro2::TokenStream; use quote::quote; use syn::Error; -/// Creates the struct that will actually store the data. This involves properly organizing the -/// fields, collecting metadata about them, reversing the order everything is stored in, and -/// converting any uses of 'this to 'static. +/// Creates the struct that will actually store the data. pub fn create_actual_struct_def(info: &StructInfo) -> Result { - let vis = utils::submodule_contents_visiblity(&info.vis); + let visibility = utils::submodule_contents_visiblity(&info.vis); + let mut fields = Vec::new(); + for (ty, ident) in info.generic_consumers() { + fields.push(quote! { #ident: ::core::marker::PhantomData<#ty> }); + } + let generic_params = info.generic_params(); + let generic_args = info.generic_arguments(); + let generic_where = &info.generics.where_clause; let ident = &info.ident; + let internal_ident = &info.internal_ident; + Ok(quote! { + #visibility struct #ident <#generic_params> #generic_where { + actual_data: [u8; ::core::mem::size_of::<#internal_ident<#(#generic_args),*>>()], + _alignment: [#internal_ident<#(#generic_args),*>; 0], + } + }) +} + +/// Creates a struct with fields like the original struct. Instances of the +/// "actual" struct are reinterpreted as instances of the "internal" struct +/// whenever data needs to be accessed. (This gets around the problem that +/// references passed to functions must be valid through the entire function, +/// but references *created* inside a function can be considered invalid +/// whenever, even during the duration of the function.) +pub fn create_internal_struct_def(info: &StructInfo) -> Result { + let vis = quote! { pub(super) }; + let ident = &info.internal_ident; let generics = &info.generics; let field_defs: Vec<_> = info diff --git a/ouroboros_macro/src/generate/try_constructor.rs b/ouroboros_macro/src/generate/try_constructor.rs index 4078c56..a5469d6 100644 --- a/ouroboros_macro/src/generate/try_constructor.rs +++ b/ouroboros_macro/src/generate/try_constructor.rs @@ -223,6 +223,7 @@ pub fn create_try_builder_and_constructor( quote! { #struct_name::#or_recover_ident(#(#builder_struct_field_names),*).map_err(|(error, _heads)| error) } }; let field_names: Vec<_> = info.fields.iter().map(|field| field.name.clone()).collect(); + let internal_ident = &info.internal_ident; let constructor_def = quote! { #documentation #visibility #constructor_fn(#(#params),*) -> ::core::result::Result<#struct_name <#(#generic_args),*>, Error_> { @@ -231,7 +232,9 @@ pub fn create_try_builder_and_constructor( #or_recover_documentation #visibility #or_recover_constructor_fn(#(#params),*) -> ::core::result::Result<#struct_name <#(#generic_args),*>, (Error_, Heads<#(#generic_args),*>)> { #(#or_recover_code)* - ::core::result::Result::Ok(Self { #(#field_names),* }) + ::core::result::Result::Ok(unsafe { + ::core::mem::transmute(#internal_ident { #(#field_names),* }) + }) } }; builder_struct_generic_producers.push(quote! { Error_ }); diff --git a/ouroboros_macro/src/generate/with_all.rs b/ouroboros_macro/src/generate/with_all.rs index e6a2665..03e3d59 100644 --- a/ouroboros_macro/src/generate/with_all.rs +++ b/ouroboros_macro/src/generate/with_all.rs @@ -16,19 +16,20 @@ pub fn make_with_all_function( let mut field_assignments = Vec::new(); let mut mut_fields = Vec::new(); let mut mut_field_assignments = Vec::new(); + let internal_struct = &info.internal_ident; // I don't think the reverse is necessary but it does make the expanded code more uniform. for field in info.fields.iter().rev() { let field_name = &field.name; let field_type = &field.typ; if field.field_type == FieldType::Tail { fields.push(quote! { #visibility #field_name: &'outer_borrow #field_type }); - field_assignments.push(quote! { #field_name: &self.#field_name }); + field_assignments.push(quote! { #field_name: &this.#field_name }); mut_fields.push(quote! { #visibility #field_name: &'outer_borrow mut #field_type }); - mut_field_assignments.push(quote! { #field_name: &mut self.#field_name }); + mut_field_assignments.push(quote! { #field_name: &mut this.#field_name }); } else if field.field_type == FieldType::Borrowed { let ass = quote! { #field_name: unsafe { ::ouroboros::macro_help::change_lifetime( - &*self.#field_name + &*this.#field_name ) } }; fields.push(quote! { #visibility #field_name: &'this #field_type }); @@ -108,6 +109,7 @@ pub fn make_with_all_function( } else { quote! { #[doc(hidden)] } }; + let generic_args = info.generic_arguments(); let fn_defs = quote! { #documentation #[inline(always)] @@ -115,6 +117,7 @@ pub fn make_with_all_function( &'outer_borrow self, user: impl for<'this> ::core::ops::FnOnce(#borrowed_fields_type) -> ReturnType ) -> ReturnType { + let this: &#internal_struct<#(#generic_args),*> = unsafe { ::core::mem::transmute(self) }; user(BorrowedFields { #(#field_assignments),* }) @@ -125,6 +128,7 @@ pub fn make_with_all_function( &'outer_borrow mut self, user: impl for<'this> ::core::ops::FnOnce(#borrowed_mut_fields_type) -> ReturnType ) -> ReturnType { + let this: &mut #internal_struct<#(#generic_args),*> = unsafe { ::core::mem::transmute(self) }; user(BorrowedMutFields { #(#mut_field_assignments),* }) diff --git a/ouroboros_macro/src/generate/with_each.rs b/ouroboros_macro/src/generate/with_each.rs index 8985857..15b0461 100644 --- a/ouroboros_macro/src/generate/with_each.rs +++ b/ouroboros_macro/src/generate/with_each.rs @@ -5,6 +5,8 @@ use syn::Error; pub fn make_with_functions(info: &StructInfo, options: Options) -> Result, Error> { let mut users = Vec::new(); + let internal_struct = &info.internal_ident; + let generic_args = info.generic_arguments(); for field in &info.fields { let visibility = &field.vis; let field_name = &field.name; @@ -34,7 +36,8 @@ pub fn make_with_functions(info: &StructInfo, options: Options) -> Result ::core::ops::FnOnce(&'outer_borrow #field_type) -> ReturnType, ) -> ReturnType { - user(&self. #field_name) + let this: &#internal_struct<#(#generic_args),*> = unsafe { ::core::mem::transmute(self) }; + user(&this. #field_name) } }); if field.covariant == Some(true) { @@ -45,7 +48,8 @@ pub fn make_with_functions(info: &StructInfo, options: Options) -> Result( &'this self, ) -> &'this #field_type { - &self.#field_name + let this: &#internal_struct<#(#generic_args),*> = unsafe { ::core::mem::transmute(self) }; + &this.#field_name } }); } else if field.covariant.is_none() { @@ -76,7 +80,8 @@ pub fn make_with_functions(info: &StructInfo, options: Options) -> Result ::core::ops::FnOnce(&'outer_borrow mut #field_type) -> ReturnType, ) -> ReturnType { - user(&mut self. #field_name) + let this: &mut #internal_struct<#(#generic_args),*> = unsafe { ::core::mem::transmute(self) }; + user(&mut this. #field_name) } }); } else if field.field_type == FieldType::Borrowed { @@ -102,7 +107,8 @@ pub fn make_with_functions(info: &StructInfo, options: Options) -> Result ::core::ops::FnOnce(&'outer_borrow #field_type) -> ReturnType, ) -> ReturnType { - user(&*self.#field_name) + let this: &#internal_struct<#(#generic_args),*> = unsafe { ::core::mem::transmute(self) }; + user(&*this.#field_name) } }); if field.self_referencing { @@ -120,7 +126,8 @@ pub fn make_with_functions(info: &StructInfo, options: Options) -> Result( &'this self, ) -> &'this #field_type { - &*self.#field_name + let this: &#internal_struct<#(#generic_args),*> = unsafe { ::core::mem::transmute(self) }; + &*this.#field_name } }); } else if field.field_type == FieldType::BorrowedMut { diff --git a/ouroboros_macro/src/info_structures.rs b/ouroboros_macro/src/info_structures.rs index 22e4cde..f2b0cc0 100644 --- a/ouroboros_macro/src/info_structures.rs +++ b/ouroboros_macro/src/info_structures.rs @@ -12,6 +12,16 @@ pub struct Options { pub do_pub_extras: bool, } +impl Options { + pub fn documentation_to_tokens(&self, documentation: &str) -> TokenStream { + if self.do_no_doc { + quote! { #[doc(hidden)] } + } else { + quote! { #[doc=#documentation] } + } + } +} + #[derive(Clone, Copy, PartialEq)] pub enum FieldType { /// Not borrowed by other parts of the struct. @@ -61,6 +71,7 @@ impl BuilderType { pub struct StructInfo { pub derives: Vec, pub ident: Ident, + pub internal_ident: Ident, pub generics: Generics, pub vis: Visibility, pub fields: Vec, diff --git a/ouroboros_macro/src/lib.rs b/ouroboros_macro/src/lib.rs index cd12419..d0a6898 100644 --- a/ouroboros_macro/src/lib.rs +++ b/ouroboros_macro/src/lib.rs @@ -9,7 +9,7 @@ mod utils; use crate::{ generate::{ constructor::create_builder_and_constructor, derives::create_derives, - into_heads::make_into_heads, struc::create_actual_struct_def, + into_heads::make_into_heads, struc::create_internal_struct_def, summon_checker::generate_checker_summoner, try_constructor::create_try_builder_and_constructor, type_asserts::make_type_asserts, with_all::make_with_all_function, with_each::make_with_functions, @@ -17,6 +17,7 @@ use crate::{ info_structures::Options, parse::parse_struct, }; +use generate::struc::create_actual_struct_def; use inflector::Inflector; use info_structures::BuilderType; use proc_macro::TokenStream; @@ -37,6 +38,7 @@ fn self_referencing_impl( let info = parse_struct(original_struct_def)?; let actual_struct_def = create_actual_struct_def(&info)?; + let internal_struct_def = create_internal_struct_def(&info)?; let borrowchk_summoner = generate_checker_summoner(&info)?; @@ -78,6 +80,7 @@ fn self_referencing_impl( use super::*; #[doc="The self-referencing struct."] #actual_struct_def + #internal_struct_def #borrowchk_summoner #builder_def #async_builder_def diff --git a/ouroboros_macro/src/parse.rs b/ouroboros_macro/src/parse.rs index 546aa7c..8d5fd1a 100644 --- a/ouroboros_macro/src/parse.rs +++ b/ouroboros_macro/src/parse.rs @@ -262,6 +262,7 @@ pub fn parse_struct(def: &ItemStruct) -> Result { return Ok(StructInfo { derives, ident: def.ident.clone(), + internal_ident: format_ident!("{}Internal", def.ident), generics: def.generics.clone(), fields, vis, From 30637694c97b231196e133b92da6a84336ee1216 Mon Sep 17 00:00:00 2001 From: joshua-maros <60271685+joshua-maros@users.noreply.github.com> Date: Sun, 11 Jun 2023 18:23:55 -0500 Subject: [PATCH 3/8] Blah. --- examples/src/ok_tests.rs | 92 ++++++++++----------- ouroboros_macro/src/generate/constructor.rs | 11 +-- ouroboros_macro/src/generate/drop.rs | 28 +++++++ ouroboros_macro/src/generate/into_heads.rs | 2 +- ouroboros_macro/src/generate/mod.rs | 1 + ouroboros_macro/src/generate/struc.rs | 6 +- ouroboros_macro/src/info_structures.rs | 24 +++++- ouroboros_macro/src/lib.rs | 4 +- ouroboros_macro/src/parse.rs | 12 +++ ouroboros_macro/src/utils.rs | 4 +- 10 files changed, 123 insertions(+), 61 deletions(-) create mode 100644 ouroboros_macro/src/generate/drop.rs diff --git a/examples/src/ok_tests.rs b/examples/src/ok_tests.rs index db27303..7a08614 100644 --- a/examples/src/ok_tests.rs +++ b/examples/src/ok_tests.rs @@ -1,9 +1,5 @@ -use alloc::borrow::ToOwned; use alloc::boxed::Box; -use alloc::vec; -use alloc::vec::Vec; use core::fmt::Debug; -use ouroboros::macro_help::AliasableBox; use ouroboros::self_referencing; @@ -54,32 +50,32 @@ struct AutoDetectCovarianceOnFieldsWithoutThis { self_reference: &'this (), } -/// This test just makes sure that the macro copes with a ton of template parameters being thrown at -/// it, specifically checking that the templates work fine even when a generated struct doesn't need -/// all of them. (E.G. heads will only contain 'd, A, and B.) -#[self_referencing] -struct TemplateMess<'d, A, B: 'static, C: 'static> -where - A: ?Sized, - B: 'static, - C: 'static, -{ - external: &'d A, - data1: B, - #[borrows(data1)] - data2: &'this C, - data3: B, - #[borrows(mut data3)] - data4: &'this mut C, -} +// /// This test just makes sure that the macro copes with a ton of template parameters being thrown at +// /// it, specifically checking that the templates work fine even when a generated struct doesn't need +// /// all of them. (E.G. heads will only contain 'd, A, and B.) +// #[self_referencing] +// struct TemplateMess<'d, A, B: 'static, C: 'static> +// where +// A: ?Sized, +// B: 'static, +// C: 'static, +// { +// external: &'d A, +// data1: B, +// #[borrows(data1)] +// data2: &'this C, +// data3: B, +// #[borrows(mut data3)] +// data4: &'this mut C, +// } -/// Regression test for #46 -#[self_referencing] -struct PreviouslyBrokeAutoGeneratedChecker { - x: T, - #[borrows(mut x)] - y: &'this (), -} +// /// Regression test for #46 +// #[self_referencing] +// struct PreviouslyBrokeAutoGeneratedChecker { +// x: T, +// #[borrows(mut x)] +// y: &'this (), +// } #[test] fn box_and_ref() { @@ -204,25 +200,25 @@ fn box_and_mut_ref() { assert!(bar.with_dref(|dref| **dref) == 34); } -#[test] -fn template_mess() { - let ext_str = "Hello World!".to_owned(); - let mut instance = TemplateMessBuilder { - external: &ext_str[..], - data1: "asdf".to_owned(), - data2_builder: |data1_contents| data1_contents, - data3: "asdf".to_owned(), - data4_builder: |data3_contents| data3_contents, - } - .build(); - instance.with_external(|ext| assert_eq!(*ext, "Hello World!")); - instance.with_data1(|data| assert_eq!(data, "asdf")); - instance.with_data4_mut(|con| **con = "Modified".to_owned()); - instance.with(|fields| { - assert!(**fields.data1 == **fields.data2); - assert!(*fields.data4 == "Modified"); - }); -} +// #[test] +// fn template_mess() { +// let ext_str = "Hello World!".to_owned(); +// let mut instance = TemplateMessBuilder { +// external: &ext_str[..], +// data1: "asdf".to_owned(), +// data2_builder: |data1_contents| data1_contents, +// data3: "asdf".to_owned(), +// data4_builder: |data3_contents| data3_contents, +// } +// .build(); +// instance.with_external(|ext| assert_eq!(*ext, "Hello World!")); +// instance.with_data1(|data| assert_eq!(data, "asdf")); +// instance.with_data4_mut(|con| **con = "Modified".to_owned()); +// instance.with(|fields| { +// assert!(**fields.data1 == **fields.data2); +// assert!(*fields.data4 == "Modified"); +// }); +// } const STATIC_INT: i32 = 456; #[test] diff --git a/ouroboros_macro/src/generate/constructor.rs b/ouroboros_macro/src/generate/constructor.rs index 2ece184..60583d8 100644 --- a/ouroboros_macro/src/generate/constructor.rs +++ b/ouroboros_macro/src/generate/constructor.rs @@ -13,6 +13,7 @@ pub fn create_builder_and_constructor( ) -> Result<(Ident, TokenStream, TokenStream), Error> { let struct_name = info.ident.clone(); let generic_args = info.generic_arguments(); + let generic_args_with_static_lifetimes = info.generic_arguments_with_static_lifetimes(); let vis = if options.do_pub_extras { info.vis.clone() @@ -159,16 +160,16 @@ pub fn create_builder_and_constructor( #documentation #vis #constructor_fn(#(#params),*) -> #struct_name <#(#generic_args),*> { ::ouroboros::macro_help::const_assert_eq!( - ::core::mem::size_of::<#struct_name<#(#generic_args),*>>(), - ::core::mem::size_of::<#internal_ident<#(#generic_args),*>>() + ::core::mem::size_of::<#struct_name<#(#generic_args_with_static_lifetimes),*>>(), + ::core::mem::size_of::<#internal_ident<#(#generic_args_with_static_lifetimes),*>>() ); ::ouroboros::macro_help::const_assert_eq!( - ::core::mem::align_of::<#struct_name<#(#generic_args),*>>(), - ::core::mem::align_of::<#internal_ident<#(#generic_args),*>>() + ::core::mem::align_of::<#struct_name<#(#generic_args_with_static_lifetimes),*>>(), + ::core::mem::align_of::<#internal_ident<#(#generic_args_with_static_lifetimes),*>>() ); #(#code)* unsafe { - ::core::mem::transmute(#internal_ident<#(#generic_args),*> { + ::core::mem::transmute(#internal_ident::<#(#generic_args),*> { #(#field_names),* }) } diff --git a/ouroboros_macro/src/generate/drop.rs b/ouroboros_macro/src/generate/drop.rs new file mode 100644 index 0000000..a78d5e1 --- /dev/null +++ b/ouroboros_macro/src/generate/drop.rs @@ -0,0 +1,28 @@ +use crate::{ + info_structures::StructInfo, + utils::{self, replace_this_with_lifetime}, +}; +use proc_macro2::TokenStream; +use quote::quote; +use syn::Error; + +pub fn create_drop_impl(info: &StructInfo) -> Result { + let ident = &info.ident; + let internal_ident = &info.internal_ident; + let generics = &info.generics; + let generic_args = info.generic_arguments(); + + let mut where_clause = quote! {}; + if let Some(clause) = &generics.where_clause { + where_clause = quote! { #clause }; + } + Ok(quote! { + impl #generics ::core::ops::Drop for #ident<#(#generic_args,)*> #where_clause { + fn drop(&mut self) { + unsafe { + ::core::ptr::drop_in_place(::core::mem::transmute::<_, *mut #internal_ident <#(#generic_args,)*>>(self)); + } + } + } + }) +} diff --git a/ouroboros_macro/src/generate/into_heads.rs b/ouroboros_macro/src/generate/into_heads.rs index 12016a8..2acb67d 100644 --- a/ouroboros_macro/src/generate/into_heads.rs +++ b/ouroboros_macro/src/generate/into_heads.rs @@ -1,5 +1,5 @@ use proc_macro2::TokenStream; -use quote::{format_ident, quote}; +use quote::quote; use crate::info_structures::{Options, StructInfo}; diff --git a/ouroboros_macro/src/generate/mod.rs b/ouroboros_macro/src/generate/mod.rs index 0b229d1..4ba6a3e 100644 --- a/ouroboros_macro/src/generate/mod.rs +++ b/ouroboros_macro/src/generate/mod.rs @@ -1,5 +1,6 @@ pub mod constructor; pub mod derives; +pub mod drop; pub mod into_heads; pub mod struc; pub mod summon_checker; diff --git a/ouroboros_macro/src/generate/struc.rs b/ouroboros_macro/src/generate/struc.rs index 8a7b9f4..28f6197 100644 --- a/ouroboros_macro/src/generate/struc.rs +++ b/ouroboros_macro/src/generate/struc.rs @@ -14,7 +14,7 @@ pub fn create_actual_struct_def(info: &StructInfo) -> Result fields.push(quote! { #ident: ::core::marker::PhantomData<#ty> }); } let generic_params = info.generic_params(); - let generic_args = info.generic_arguments(); + let generic_args = info.generic_arguments_with_static_lifetimes(); let generic_where = &info.generics.where_clause; let ident = &info.ident; let internal_ident = &info.internal_ident; @@ -22,6 +22,7 @@ pub fn create_actual_struct_def(info: &StructInfo) -> Result #visibility struct #ident <#generic_params> #generic_where { actual_data: [u8; ::core::mem::size_of::<#internal_ident<#(#generic_args),*>>()], _alignment: [#internal_ident<#(#generic_args),*>; 0], + #(#fields),* } }) } @@ -33,7 +34,6 @@ pub fn create_actual_struct_def(info: &StructInfo) -> Result /// but references *created* inside a function can be considered invalid /// whenever, even during the duration of the function.) pub fn create_internal_struct_def(info: &StructInfo) -> Result { - let vis = quote! { pub(super) }; let ident = &info.internal_ident; let generics = &info.generics; @@ -60,7 +60,7 @@ pub fn create_internal_struct_def(info: &StructInfo) -> Result Vec<&GenericParam> { + self.generics + .params + .iter() + .filter(|p| { + if let GenericParam::Lifetime(..) = p { + false + } else { + true + } + }) + .collect() + } + /// Same as generic_params but with 'this and 'outer_borrow prepended. pub fn borrowed_generic_params(&self) -> TokenStream { if self.generic_params().is_empty() { @@ -115,7 +129,15 @@ impl StructInfo { } pub fn generic_arguments(&self) -> Vec { - make_generic_arguments(&self.generics) + make_generic_arguments(self.generics.params.iter().collect()) + } + + pub fn generic_arguments_with_static_lifetimes(&self) -> Vec { + let mut result = make_generic_arguments(self.generic_params_without_lifetimes()); + for _ in 0..self.generics.lifetimes().count() { + result.insert(0, quote! { 'static }); + } + result } /// Same as generic_arguments but with 'outer_borrow and 'this prepended. diff --git a/ouroboros_macro/src/lib.rs b/ouroboros_macro/src/lib.rs index d0a6898..c46584c 100644 --- a/ouroboros_macro/src/lib.rs +++ b/ouroboros_macro/src/lib.rs @@ -17,7 +17,7 @@ use crate::{ info_structures::Options, parse::parse_struct, }; -use generate::struc::create_actual_struct_def; +use generate::{struc::create_actual_struct_def, drop::create_drop_impl}; use inflector::Inflector; use info_structures::BuilderType; use proc_macro::TokenStream; @@ -39,6 +39,7 @@ fn self_referencing_impl( let actual_struct_def = create_actual_struct_def(&info)?; let internal_struct_def = create_internal_struct_def(&info)?; + let drop_impl = create_drop_impl(&info)?; let borrowchk_summoner = generate_checker_summoner(&info)?; @@ -81,6 +82,7 @@ fn self_referencing_impl( #[doc="The self-referencing struct."] #actual_struct_def #internal_struct_def + #drop_impl #borrowchk_summoner #builder_def #async_builder_def diff --git a/ouroboros_macro/src/parse.rs b/ouroboros_macro/src/parse.rs index 8d5fd1a..a01d9a8 100644 --- a/ouroboros_macro/src/parse.rs +++ b/ouroboros_macro/src/parse.rs @@ -133,6 +133,18 @@ fn parse_derive_attribute(attr: &Attribute) -> Result, Error> { pub fn parse_struct(def: &ItemStruct) -> Result { let vis = def.vis.clone(); let generics = def.generics.clone(); + if let Some(first_param) = generics.type_params().next() { + return Err(Error::new( + first_param.span(), + "Self-referencing structs currently cannot have type or constant parameters, only lifetime parameters.", + )); + } + if let Some(first_param) = generics.const_params().next() { + return Err(Error::new( + first_param.span(), + "Self-referencing structs currently cannot have type or constant parameters, only lifetime parameters.", + )); + } let mut actual_struct_def = def.clone(); actual_struct_def.vis = vis.clone(); let mut fields = Vec::new(); diff --git a/ouroboros_macro/src/utils.rs b/ouroboros_macro/src/utils.rs index 5bbae6c..3b1f770 100644 --- a/ouroboros_macro/src/utils.rs +++ b/ouroboros_macro/src/utils.rs @@ -33,9 +33,9 @@ pub fn make_generic_consumers(generics: &Generics) -> impl Iterator Vec { +pub fn make_generic_arguments(generics: Vec<&GenericParam>) -> Vec { let mut arguments = Vec::new(); - for generic in generics.params.clone() { + for generic in generics { match generic { GenericParam::Type(typ) => { let ident = &typ.ident; From 71de8eb50cd9cab027f85fae7ce8caa04584aab5 Mon Sep 17 00:00:00 2001 From: joshua-maros <60271685+joshua-maros@users.noreply.github.com> Date: Sun, 11 Jun 2023 18:24:07 -0500 Subject: [PATCH 4/8] Revert "Blah." This reverts commit 30637694c97b231196e133b92da6a84336ee1216. --- examples/src/ok_tests.rs | 92 +++++++++++---------- ouroboros_macro/src/generate/constructor.rs | 11 ++- ouroboros_macro/src/generate/drop.rs | 28 ------- ouroboros_macro/src/generate/into_heads.rs | 2 +- ouroboros_macro/src/generate/mod.rs | 1 - ouroboros_macro/src/generate/struc.rs | 6 +- ouroboros_macro/src/info_structures.rs | 24 +----- ouroboros_macro/src/lib.rs | 4 +- ouroboros_macro/src/parse.rs | 12 --- ouroboros_macro/src/utils.rs | 4 +- 10 files changed, 61 insertions(+), 123 deletions(-) delete mode 100644 ouroboros_macro/src/generate/drop.rs diff --git a/examples/src/ok_tests.rs b/examples/src/ok_tests.rs index 7a08614..db27303 100644 --- a/examples/src/ok_tests.rs +++ b/examples/src/ok_tests.rs @@ -1,5 +1,9 @@ +use alloc::borrow::ToOwned; use alloc::boxed::Box; +use alloc::vec; +use alloc::vec::Vec; use core::fmt::Debug; +use ouroboros::macro_help::AliasableBox; use ouroboros::self_referencing; @@ -50,32 +54,32 @@ struct AutoDetectCovarianceOnFieldsWithoutThis { self_reference: &'this (), } -// /// This test just makes sure that the macro copes with a ton of template parameters being thrown at -// /// it, specifically checking that the templates work fine even when a generated struct doesn't need -// /// all of them. (E.G. heads will only contain 'd, A, and B.) -// #[self_referencing] -// struct TemplateMess<'d, A, B: 'static, C: 'static> -// where -// A: ?Sized, -// B: 'static, -// C: 'static, -// { -// external: &'d A, -// data1: B, -// #[borrows(data1)] -// data2: &'this C, -// data3: B, -// #[borrows(mut data3)] -// data4: &'this mut C, -// } +/// This test just makes sure that the macro copes with a ton of template parameters being thrown at +/// it, specifically checking that the templates work fine even when a generated struct doesn't need +/// all of them. (E.G. heads will only contain 'd, A, and B.) +#[self_referencing] +struct TemplateMess<'d, A, B: 'static, C: 'static> +where + A: ?Sized, + B: 'static, + C: 'static, +{ + external: &'d A, + data1: B, + #[borrows(data1)] + data2: &'this C, + data3: B, + #[borrows(mut data3)] + data4: &'this mut C, +} -// /// Regression test for #46 -// #[self_referencing] -// struct PreviouslyBrokeAutoGeneratedChecker { -// x: T, -// #[borrows(mut x)] -// y: &'this (), -// } +/// Regression test for #46 +#[self_referencing] +struct PreviouslyBrokeAutoGeneratedChecker { + x: T, + #[borrows(mut x)] + y: &'this (), +} #[test] fn box_and_ref() { @@ -200,25 +204,25 @@ fn box_and_mut_ref() { assert!(bar.with_dref(|dref| **dref) == 34); } -// #[test] -// fn template_mess() { -// let ext_str = "Hello World!".to_owned(); -// let mut instance = TemplateMessBuilder { -// external: &ext_str[..], -// data1: "asdf".to_owned(), -// data2_builder: |data1_contents| data1_contents, -// data3: "asdf".to_owned(), -// data4_builder: |data3_contents| data3_contents, -// } -// .build(); -// instance.with_external(|ext| assert_eq!(*ext, "Hello World!")); -// instance.with_data1(|data| assert_eq!(data, "asdf")); -// instance.with_data4_mut(|con| **con = "Modified".to_owned()); -// instance.with(|fields| { -// assert!(**fields.data1 == **fields.data2); -// assert!(*fields.data4 == "Modified"); -// }); -// } +#[test] +fn template_mess() { + let ext_str = "Hello World!".to_owned(); + let mut instance = TemplateMessBuilder { + external: &ext_str[..], + data1: "asdf".to_owned(), + data2_builder: |data1_contents| data1_contents, + data3: "asdf".to_owned(), + data4_builder: |data3_contents| data3_contents, + } + .build(); + instance.with_external(|ext| assert_eq!(*ext, "Hello World!")); + instance.with_data1(|data| assert_eq!(data, "asdf")); + instance.with_data4_mut(|con| **con = "Modified".to_owned()); + instance.with(|fields| { + assert!(**fields.data1 == **fields.data2); + assert!(*fields.data4 == "Modified"); + }); +} const STATIC_INT: i32 = 456; #[test] diff --git a/ouroboros_macro/src/generate/constructor.rs b/ouroboros_macro/src/generate/constructor.rs index 60583d8..2ece184 100644 --- a/ouroboros_macro/src/generate/constructor.rs +++ b/ouroboros_macro/src/generate/constructor.rs @@ -13,7 +13,6 @@ pub fn create_builder_and_constructor( ) -> Result<(Ident, TokenStream, TokenStream), Error> { let struct_name = info.ident.clone(); let generic_args = info.generic_arguments(); - let generic_args_with_static_lifetimes = info.generic_arguments_with_static_lifetimes(); let vis = if options.do_pub_extras { info.vis.clone() @@ -160,16 +159,16 @@ pub fn create_builder_and_constructor( #documentation #vis #constructor_fn(#(#params),*) -> #struct_name <#(#generic_args),*> { ::ouroboros::macro_help::const_assert_eq!( - ::core::mem::size_of::<#struct_name<#(#generic_args_with_static_lifetimes),*>>(), - ::core::mem::size_of::<#internal_ident<#(#generic_args_with_static_lifetimes),*>>() + ::core::mem::size_of::<#struct_name<#(#generic_args),*>>(), + ::core::mem::size_of::<#internal_ident<#(#generic_args),*>>() ); ::ouroboros::macro_help::const_assert_eq!( - ::core::mem::align_of::<#struct_name<#(#generic_args_with_static_lifetimes),*>>(), - ::core::mem::align_of::<#internal_ident<#(#generic_args_with_static_lifetimes),*>>() + ::core::mem::align_of::<#struct_name<#(#generic_args),*>>(), + ::core::mem::align_of::<#internal_ident<#(#generic_args),*>>() ); #(#code)* unsafe { - ::core::mem::transmute(#internal_ident::<#(#generic_args),*> { + ::core::mem::transmute(#internal_ident<#(#generic_args),*> { #(#field_names),* }) } diff --git a/ouroboros_macro/src/generate/drop.rs b/ouroboros_macro/src/generate/drop.rs deleted file mode 100644 index a78d5e1..0000000 --- a/ouroboros_macro/src/generate/drop.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::{ - info_structures::StructInfo, - utils::{self, replace_this_with_lifetime}, -}; -use proc_macro2::TokenStream; -use quote::quote; -use syn::Error; - -pub fn create_drop_impl(info: &StructInfo) -> Result { - let ident = &info.ident; - let internal_ident = &info.internal_ident; - let generics = &info.generics; - let generic_args = info.generic_arguments(); - - let mut where_clause = quote! {}; - if let Some(clause) = &generics.where_clause { - where_clause = quote! { #clause }; - } - Ok(quote! { - impl #generics ::core::ops::Drop for #ident<#(#generic_args,)*> #where_clause { - fn drop(&mut self) { - unsafe { - ::core::ptr::drop_in_place(::core::mem::transmute::<_, *mut #internal_ident <#(#generic_args,)*>>(self)); - } - } - } - }) -} diff --git a/ouroboros_macro/src/generate/into_heads.rs b/ouroboros_macro/src/generate/into_heads.rs index 2acb67d..12016a8 100644 --- a/ouroboros_macro/src/generate/into_heads.rs +++ b/ouroboros_macro/src/generate/into_heads.rs @@ -1,5 +1,5 @@ use proc_macro2::TokenStream; -use quote::quote; +use quote::{format_ident, quote}; use crate::info_structures::{Options, StructInfo}; diff --git a/ouroboros_macro/src/generate/mod.rs b/ouroboros_macro/src/generate/mod.rs index 4ba6a3e..0b229d1 100644 --- a/ouroboros_macro/src/generate/mod.rs +++ b/ouroboros_macro/src/generate/mod.rs @@ -1,6 +1,5 @@ pub mod constructor; pub mod derives; -pub mod drop; pub mod into_heads; pub mod struc; pub mod summon_checker; diff --git a/ouroboros_macro/src/generate/struc.rs b/ouroboros_macro/src/generate/struc.rs index 28f6197..8a7b9f4 100644 --- a/ouroboros_macro/src/generate/struc.rs +++ b/ouroboros_macro/src/generate/struc.rs @@ -14,7 +14,7 @@ pub fn create_actual_struct_def(info: &StructInfo) -> Result fields.push(quote! { #ident: ::core::marker::PhantomData<#ty> }); } let generic_params = info.generic_params(); - let generic_args = info.generic_arguments_with_static_lifetimes(); + let generic_args = info.generic_arguments(); let generic_where = &info.generics.where_clause; let ident = &info.ident; let internal_ident = &info.internal_ident; @@ -22,7 +22,6 @@ pub fn create_actual_struct_def(info: &StructInfo) -> Result #visibility struct #ident <#generic_params> #generic_where { actual_data: [u8; ::core::mem::size_of::<#internal_ident<#(#generic_args),*>>()], _alignment: [#internal_ident<#(#generic_args),*>; 0], - #(#fields),* } }) } @@ -34,6 +33,7 @@ pub fn create_actual_struct_def(info: &StructInfo) -> Result /// but references *created* inside a function can be considered invalid /// whenever, even during the duration of the function.) pub fn create_internal_struct_def(info: &StructInfo) -> Result { + let vis = quote! { pub(super) }; let ident = &info.internal_ident; let generics = &info.generics; @@ -60,7 +60,7 @@ pub fn create_internal_struct_def(info: &StructInfo) -> Result Vec<&GenericParam> { - self.generics - .params - .iter() - .filter(|p| { - if let GenericParam::Lifetime(..) = p { - false - } else { - true - } - }) - .collect() - } - /// Same as generic_params but with 'this and 'outer_borrow prepended. pub fn borrowed_generic_params(&self) -> TokenStream { if self.generic_params().is_empty() { @@ -129,15 +115,7 @@ impl StructInfo { } pub fn generic_arguments(&self) -> Vec { - make_generic_arguments(self.generics.params.iter().collect()) - } - - pub fn generic_arguments_with_static_lifetimes(&self) -> Vec { - let mut result = make_generic_arguments(self.generic_params_without_lifetimes()); - for _ in 0..self.generics.lifetimes().count() { - result.insert(0, quote! { 'static }); - } - result + make_generic_arguments(&self.generics) } /// Same as generic_arguments but with 'outer_borrow and 'this prepended. diff --git a/ouroboros_macro/src/lib.rs b/ouroboros_macro/src/lib.rs index c46584c..d0a6898 100644 --- a/ouroboros_macro/src/lib.rs +++ b/ouroboros_macro/src/lib.rs @@ -17,7 +17,7 @@ use crate::{ info_structures::Options, parse::parse_struct, }; -use generate::{struc::create_actual_struct_def, drop::create_drop_impl}; +use generate::struc::create_actual_struct_def; use inflector::Inflector; use info_structures::BuilderType; use proc_macro::TokenStream; @@ -39,7 +39,6 @@ fn self_referencing_impl( let actual_struct_def = create_actual_struct_def(&info)?; let internal_struct_def = create_internal_struct_def(&info)?; - let drop_impl = create_drop_impl(&info)?; let borrowchk_summoner = generate_checker_summoner(&info)?; @@ -82,7 +81,6 @@ fn self_referencing_impl( #[doc="The self-referencing struct."] #actual_struct_def #internal_struct_def - #drop_impl #borrowchk_summoner #builder_def #async_builder_def diff --git a/ouroboros_macro/src/parse.rs b/ouroboros_macro/src/parse.rs index a01d9a8..8d5fd1a 100644 --- a/ouroboros_macro/src/parse.rs +++ b/ouroboros_macro/src/parse.rs @@ -133,18 +133,6 @@ fn parse_derive_attribute(attr: &Attribute) -> Result, Error> { pub fn parse_struct(def: &ItemStruct) -> Result { let vis = def.vis.clone(); let generics = def.generics.clone(); - if let Some(first_param) = generics.type_params().next() { - return Err(Error::new( - first_param.span(), - "Self-referencing structs currently cannot have type or constant parameters, only lifetime parameters.", - )); - } - if let Some(first_param) = generics.const_params().next() { - return Err(Error::new( - first_param.span(), - "Self-referencing structs currently cannot have type or constant parameters, only lifetime parameters.", - )); - } let mut actual_struct_def = def.clone(); actual_struct_def.vis = vis.clone(); let mut fields = Vec::new(); diff --git a/ouroboros_macro/src/utils.rs b/ouroboros_macro/src/utils.rs index 3b1f770..5bbae6c 100644 --- a/ouroboros_macro/src/utils.rs +++ b/ouroboros_macro/src/utils.rs @@ -33,9 +33,9 @@ pub fn make_generic_consumers(generics: &Generics) -> impl Iterator) -> Vec { +pub fn make_generic_arguments(generics: &Generics) -> Vec { let mut arguments = Vec::new(); - for generic in generics { + for generic in generics.params.clone() { match generic { GenericParam::Type(typ) => { let ident = &typ.ident; From 658ec36d8b41cc8820c12b1ca92e655127d6858a Mon Sep 17 00:00:00 2001 From: joshua-maros <60271685+joshua-maros@users.noreply.github.com> Date: Sun, 11 Jun 2023 18:25:16 -0500 Subject: [PATCH 5/8] Revert "Revert "Revert "Failed attempt to fix problems.""" This reverts commit c8891142dd2eb437f0dcf2c0ad170be6fbb73d9d. --- examples/Cargo.toml | 4 +-- examples/src/ok_tests.rs | 3 -- ouroboros/Cargo.toml | 5 ++- ouroboros/src/lib.rs | 1 - ouroboros_macro/Cargo.toml | 2 +- ouroboros_macro/src/generate/constructor.rs | 15 ++------- ouroboros_macro/src/generate/into_heads.rs | 14 ++++----- ouroboros_macro/src/generate/struc.rs | 31 +++---------------- .../src/generate/try_constructor.rs | 5 +-- ouroboros_macro/src/generate/with_all.rs | 10 ++---- ouroboros_macro/src/generate/with_each.rs | 17 +++------- ouroboros_macro/src/info_structures.rs | 11 ------- ouroboros_macro/src/lib.rs | 5 +-- ouroboros_macro/src/parse.rs | 1 - 14 files changed, 27 insertions(+), 97 deletions(-) diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 8243ddf..e8fa0fd 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ouroboros_examples" -version = "0.16.0" +version = "0.15.7" authors = ["Joshua Maros "] edition = "2018" license = "MIT OR Apache-2.0" @@ -21,7 +21,7 @@ std = [] __tokio = ["tokio", "std"] [dependencies] -ouroboros = { version = "0.16.0", path = "../ouroboros" } +ouroboros = { version = "0.15.7", path = "../ouroboros" } tokio = { version = "1.27.0", features = [ "macros", "rt" ], optional = true } [dev-dependencies] diff --git a/examples/src/ok_tests.rs b/examples/src/ok_tests.rs index db27303..61ae346 100644 --- a/examples/src/ok_tests.rs +++ b/examples/src/ok_tests.rs @@ -1,9 +1,6 @@ use alloc::borrow::ToOwned; use alloc::boxed::Box; -use alloc::vec; -use alloc::vec::Vec; use core::fmt::Debug; -use ouroboros::macro_help::AliasableBox; use ouroboros::self_referencing; diff --git a/ouroboros/Cargo.toml b/ouroboros/Cargo.toml index 3c256b4..4ee1ca3 100644 --- a/ouroboros/Cargo.toml +++ b/ouroboros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ouroboros" -version = "0.16.0" +version = "0.15.7" authors = ["Joshua Maros "] edition = "2018" license = "MIT OR Apache-2.0" @@ -11,8 +11,7 @@ repository = "https://github.com/joshua-maros/ouroboros" [dependencies] aliasable = "0.1.3" -ouroboros_macro = { version = "0.16.0", path = "../ouroboros_macro" } -static_assertions = "1.1.0" +ouroboros_macro = { version = "0.15.7", path = "../ouroboros_macro" } [features] default = ["std"] diff --git a/ouroboros/src/lib.rs b/ouroboros/src/lib.rs index 13870da..efd32e8 100644 --- a/ouroboros/src/lib.rs +++ b/ouroboros/src/lib.rs @@ -351,7 +351,6 @@ pub mod macro_help { pub extern crate alloc; pub use aliasable::boxed::AliasableBox; - pub use static_assertions::const_assert_eq; use aliasable::boxed::UniqueBox; pub struct CheckIfTypeIsStd(core::marker::PhantomData); diff --git a/ouroboros_macro/Cargo.toml b/ouroboros_macro/Cargo.toml index 5b2a56b..a350e81 100644 --- a/ouroboros_macro/Cargo.toml +++ b/ouroboros_macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ouroboros_macro" -version = "0.16.0" +version = "0.15.7" authors = ["Joshua Maros "] edition = "2018" license = "MIT OR Apache-2.0" diff --git a/ouroboros_macro/src/generate/constructor.rs b/ouroboros_macro/src/generate/constructor.rs index 2ece184..6ab47bc 100644 --- a/ouroboros_macro/src/generate/constructor.rs +++ b/ouroboros_macro/src/generate/constructor.rs @@ -154,23 +154,12 @@ pub fn create_builder_and_constructor( BuilderType::Sync => quote! { fn new }, }; let field_names: Vec<_> = info.fields.iter().map(|field| field.name.clone()).collect(); - let internal_ident = &info.internal_ident; let constructor_def = quote! { #documentation #vis #constructor_fn(#(#params),*) -> #struct_name <#(#generic_args),*> { - ::ouroboros::macro_help::const_assert_eq!( - ::core::mem::size_of::<#struct_name<#(#generic_args),*>>(), - ::core::mem::size_of::<#internal_ident<#(#generic_args),*>>() - ); - ::ouroboros::macro_help::const_assert_eq!( - ::core::mem::align_of::<#struct_name<#(#generic_args),*>>(), - ::core::mem::align_of::<#internal_ident<#(#generic_args),*>>() - ); #(#code)* - unsafe { - ::core::mem::transmute(#internal_ident<#(#generic_args),*> { - #(#field_names),* - }) + Self { + #(#field_names),* } } }; diff --git a/ouroboros_macro/src/generate/into_heads.rs b/ouroboros_macro/src/generate/into_heads.rs index 12016a8..5784e46 100644 --- a/ouroboros_macro/src/generate/into_heads.rs +++ b/ouroboros_macro/src/generate/into_heads.rs @@ -1,5 +1,5 @@ use proc_macro2::TokenStream; -use quote::{format_ident, quote}; +use quote::quote; use crate::info_structures::{Options, StructInfo}; @@ -13,16 +13,12 @@ pub fn make_into_heads(info: &StructInfo, options: Options) -> (TokenStream, Tok let mut code = Vec::new(); let mut field_initializers = Vec::new(); let mut head_fields = Vec::new(); - let internal_struct = &info.internal_ident; // Drop everything in the reverse order of what it was declared in. Fields that come later // are only dependent on fields that came before them. for field in info.fields.iter().rev() { let field_name = &field.name; - if field.self_referencing { - // Heads are fields that do not borrow anything. - code.push(quote! { ::core::mem::drop(this.#field_name); }); - } else { - code.push(quote! { let #field_name = this.#field_name; }); + if !field.self_referencing { + code.push(quote! { let #field_name = self.#field_name; }); if field.is_borrowed() { field_initializers .push(quote! { #field_name: ::ouroboros::macro_help::unbox(#field_name) }); @@ -31,6 +27,9 @@ pub fn make_into_heads(info: &StructInfo, options: Options) -> (TokenStream, Tok } let field_type = &field.typ; head_fields.push(quote! { #visibility #field_name: #field_type }); + } else { + // Heads are fields that do not borrow anything. + code.push(quote! { ::core::mem::drop(self.#field_name); }); } } for (ty, ident) in info.generic_consumers() { @@ -72,7 +71,6 @@ pub fn make_into_heads(info: &StructInfo, options: Options) -> (TokenStream, Tok #[allow(clippy::drop_copy)] #[allow(clippy::drop_non_drop)] #visibility fn into_heads(self) -> Heads<#(#generic_args),*> { - let this: #internal_struct<#(#generic_args),*> = unsafe { ::core::mem::transmute(self) }; #(#code)* Heads { #(#field_initializers),* diff --git a/ouroboros_macro/src/generate/struc.rs b/ouroboros_macro/src/generate/struc.rs index 8a7b9f4..9b2ff51 100644 --- a/ouroboros_macro/src/generate/struc.rs +++ b/ouroboros_macro/src/generate/struc.rs @@ -6,35 +6,12 @@ use proc_macro2::TokenStream; use quote::quote; use syn::Error; -/// Creates the struct that will actually store the data. +/// Creates the struct that will actually store the data. This involves properly organizing the +/// fields, collecting metadata about them, reversing the order everything is stored in, and +/// converting any uses of 'this to 'static. pub fn create_actual_struct_def(info: &StructInfo) -> Result { - let visibility = utils::submodule_contents_visiblity(&info.vis); - let mut fields = Vec::new(); - for (ty, ident) in info.generic_consumers() { - fields.push(quote! { #ident: ::core::marker::PhantomData<#ty> }); - } - let generic_params = info.generic_params(); - let generic_args = info.generic_arguments(); - let generic_where = &info.generics.where_clause; + let vis = utils::submodule_contents_visiblity(&info.vis); let ident = &info.ident; - let internal_ident = &info.internal_ident; - Ok(quote! { - #visibility struct #ident <#generic_params> #generic_where { - actual_data: [u8; ::core::mem::size_of::<#internal_ident<#(#generic_args),*>>()], - _alignment: [#internal_ident<#(#generic_args),*>; 0], - } - }) -} - -/// Creates a struct with fields like the original struct. Instances of the -/// "actual" struct are reinterpreted as instances of the "internal" struct -/// whenever data needs to be accessed. (This gets around the problem that -/// references passed to functions must be valid through the entire function, -/// but references *created* inside a function can be considered invalid -/// whenever, even during the duration of the function.) -pub fn create_internal_struct_def(info: &StructInfo) -> Result { - let vis = quote! { pub(super) }; - let ident = &info.internal_ident; let generics = &info.generics; let field_defs: Vec<_> = info diff --git a/ouroboros_macro/src/generate/try_constructor.rs b/ouroboros_macro/src/generate/try_constructor.rs index a5469d6..4078c56 100644 --- a/ouroboros_macro/src/generate/try_constructor.rs +++ b/ouroboros_macro/src/generate/try_constructor.rs @@ -223,7 +223,6 @@ pub fn create_try_builder_and_constructor( quote! { #struct_name::#or_recover_ident(#(#builder_struct_field_names),*).map_err(|(error, _heads)| error) } }; let field_names: Vec<_> = info.fields.iter().map(|field| field.name.clone()).collect(); - let internal_ident = &info.internal_ident; let constructor_def = quote! { #documentation #visibility #constructor_fn(#(#params),*) -> ::core::result::Result<#struct_name <#(#generic_args),*>, Error_> { @@ -232,9 +231,7 @@ pub fn create_try_builder_and_constructor( #or_recover_documentation #visibility #or_recover_constructor_fn(#(#params),*) -> ::core::result::Result<#struct_name <#(#generic_args),*>, (Error_, Heads<#(#generic_args),*>)> { #(#or_recover_code)* - ::core::result::Result::Ok(unsafe { - ::core::mem::transmute(#internal_ident { #(#field_names),* }) - }) + ::core::result::Result::Ok(Self { #(#field_names),* }) } }; builder_struct_generic_producers.push(quote! { Error_ }); diff --git a/ouroboros_macro/src/generate/with_all.rs b/ouroboros_macro/src/generate/with_all.rs index 03e3d59..e6a2665 100644 --- a/ouroboros_macro/src/generate/with_all.rs +++ b/ouroboros_macro/src/generate/with_all.rs @@ -16,20 +16,19 @@ pub fn make_with_all_function( let mut field_assignments = Vec::new(); let mut mut_fields = Vec::new(); let mut mut_field_assignments = Vec::new(); - let internal_struct = &info.internal_ident; // I don't think the reverse is necessary but it does make the expanded code more uniform. for field in info.fields.iter().rev() { let field_name = &field.name; let field_type = &field.typ; if field.field_type == FieldType::Tail { fields.push(quote! { #visibility #field_name: &'outer_borrow #field_type }); - field_assignments.push(quote! { #field_name: &this.#field_name }); + field_assignments.push(quote! { #field_name: &self.#field_name }); mut_fields.push(quote! { #visibility #field_name: &'outer_borrow mut #field_type }); - mut_field_assignments.push(quote! { #field_name: &mut this.#field_name }); + mut_field_assignments.push(quote! { #field_name: &mut self.#field_name }); } else if field.field_type == FieldType::Borrowed { let ass = quote! { #field_name: unsafe { ::ouroboros::macro_help::change_lifetime( - &*this.#field_name + &*self.#field_name ) } }; fields.push(quote! { #visibility #field_name: &'this #field_type }); @@ -109,7 +108,6 @@ pub fn make_with_all_function( } else { quote! { #[doc(hidden)] } }; - let generic_args = info.generic_arguments(); let fn_defs = quote! { #documentation #[inline(always)] @@ -117,7 +115,6 @@ pub fn make_with_all_function( &'outer_borrow self, user: impl for<'this> ::core::ops::FnOnce(#borrowed_fields_type) -> ReturnType ) -> ReturnType { - let this: &#internal_struct<#(#generic_args),*> = unsafe { ::core::mem::transmute(self) }; user(BorrowedFields { #(#field_assignments),* }) @@ -128,7 +125,6 @@ pub fn make_with_all_function( &'outer_borrow mut self, user: impl for<'this> ::core::ops::FnOnce(#borrowed_mut_fields_type) -> ReturnType ) -> ReturnType { - let this: &mut #internal_struct<#(#generic_args),*> = unsafe { ::core::mem::transmute(self) }; user(BorrowedMutFields { #(#mut_field_assignments),* }) diff --git a/ouroboros_macro/src/generate/with_each.rs b/ouroboros_macro/src/generate/with_each.rs index 15b0461..8985857 100644 --- a/ouroboros_macro/src/generate/with_each.rs +++ b/ouroboros_macro/src/generate/with_each.rs @@ -5,8 +5,6 @@ use syn::Error; pub fn make_with_functions(info: &StructInfo, options: Options) -> Result, Error> { let mut users = Vec::new(); - let internal_struct = &info.internal_ident; - let generic_args = info.generic_arguments(); for field in &info.fields { let visibility = &field.vis; let field_name = &field.name; @@ -36,8 +34,7 @@ pub fn make_with_functions(info: &StructInfo, options: Options) -> Result ::core::ops::FnOnce(&'outer_borrow #field_type) -> ReturnType, ) -> ReturnType { - let this: &#internal_struct<#(#generic_args),*> = unsafe { ::core::mem::transmute(self) }; - user(&this. #field_name) + user(&self. #field_name) } }); if field.covariant == Some(true) { @@ -48,8 +45,7 @@ pub fn make_with_functions(info: &StructInfo, options: Options) -> Result( &'this self, ) -> &'this #field_type { - let this: &#internal_struct<#(#generic_args),*> = unsafe { ::core::mem::transmute(self) }; - &this.#field_name + &self.#field_name } }); } else if field.covariant.is_none() { @@ -80,8 +76,7 @@ pub fn make_with_functions(info: &StructInfo, options: Options) -> Result ::core::ops::FnOnce(&'outer_borrow mut #field_type) -> ReturnType, ) -> ReturnType { - let this: &mut #internal_struct<#(#generic_args),*> = unsafe { ::core::mem::transmute(self) }; - user(&mut this. #field_name) + user(&mut self. #field_name) } }); } else if field.field_type == FieldType::Borrowed { @@ -107,8 +102,7 @@ pub fn make_with_functions(info: &StructInfo, options: Options) -> Result ::core::ops::FnOnce(&'outer_borrow #field_type) -> ReturnType, ) -> ReturnType { - let this: &#internal_struct<#(#generic_args),*> = unsafe { ::core::mem::transmute(self) }; - user(&*this.#field_name) + user(&*self.#field_name) } }); if field.self_referencing { @@ -126,8 +120,7 @@ pub fn make_with_functions(info: &StructInfo, options: Options) -> Result( &'this self, ) -> &'this #field_type { - let this: &#internal_struct<#(#generic_args),*> = unsafe { ::core::mem::transmute(self) }; - &*this.#field_name + &*self.#field_name } }); } else if field.field_type == FieldType::BorrowedMut { diff --git a/ouroboros_macro/src/info_structures.rs b/ouroboros_macro/src/info_structures.rs index f2b0cc0..22e4cde 100644 --- a/ouroboros_macro/src/info_structures.rs +++ b/ouroboros_macro/src/info_structures.rs @@ -12,16 +12,6 @@ pub struct Options { pub do_pub_extras: bool, } -impl Options { - pub fn documentation_to_tokens(&self, documentation: &str) -> TokenStream { - if self.do_no_doc { - quote! { #[doc(hidden)] } - } else { - quote! { #[doc=#documentation] } - } - } -} - #[derive(Clone, Copy, PartialEq)] pub enum FieldType { /// Not borrowed by other parts of the struct. @@ -71,7 +61,6 @@ impl BuilderType { pub struct StructInfo { pub derives: Vec, pub ident: Ident, - pub internal_ident: Ident, pub generics: Generics, pub vis: Visibility, pub fields: Vec, diff --git a/ouroboros_macro/src/lib.rs b/ouroboros_macro/src/lib.rs index d0a6898..cd12419 100644 --- a/ouroboros_macro/src/lib.rs +++ b/ouroboros_macro/src/lib.rs @@ -9,7 +9,7 @@ mod utils; use crate::{ generate::{ constructor::create_builder_and_constructor, derives::create_derives, - into_heads::make_into_heads, struc::create_internal_struct_def, + into_heads::make_into_heads, struc::create_actual_struct_def, summon_checker::generate_checker_summoner, try_constructor::create_try_builder_and_constructor, type_asserts::make_type_asserts, with_all::make_with_all_function, with_each::make_with_functions, @@ -17,7 +17,6 @@ use crate::{ info_structures::Options, parse::parse_struct, }; -use generate::struc::create_actual_struct_def; use inflector::Inflector; use info_structures::BuilderType; use proc_macro::TokenStream; @@ -38,7 +37,6 @@ fn self_referencing_impl( let info = parse_struct(original_struct_def)?; let actual_struct_def = create_actual_struct_def(&info)?; - let internal_struct_def = create_internal_struct_def(&info)?; let borrowchk_summoner = generate_checker_summoner(&info)?; @@ -80,7 +78,6 @@ fn self_referencing_impl( use super::*; #[doc="The self-referencing struct."] #actual_struct_def - #internal_struct_def #borrowchk_summoner #builder_def #async_builder_def diff --git a/ouroboros_macro/src/parse.rs b/ouroboros_macro/src/parse.rs index 8d5fd1a..546aa7c 100644 --- a/ouroboros_macro/src/parse.rs +++ b/ouroboros_macro/src/parse.rs @@ -262,7 +262,6 @@ pub fn parse_struct(def: &ItemStruct) -> Result { return Ok(StructInfo { derives, ident: def.ident.clone(), - internal_ident: format_ident!("{}Internal", def.ident), generics: def.generics.clone(), fields, vis, From adb5763317ae1e6a3d6eacf9671e4435403c027a Mon Sep 17 00:00:00 2001 From: joshua-maros <60271685+joshua-maros@users.noreply.github.com> Date: Tue, 13 Jun 2023 20:50:01 -0500 Subject: [PATCH 6/8] Fix --- ouroboros_macro/src/generate/struc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ouroboros_macro/src/generate/struc.rs b/ouroboros_macro/src/generate/struc.rs index 28f6197..bc9b5d4 100644 --- a/ouroboros_macro/src/generate/struc.rs +++ b/ouroboros_macro/src/generate/struc.rs @@ -20,7 +20,7 @@ pub fn create_actual_struct_def(info: &StructInfo) -> Result let internal_ident = &info.internal_ident; Ok(quote! { #visibility struct #ident <#generic_params> #generic_where { - actual_data: [u8; ::core::mem::size_of::<#internal_ident<#(#generic_args),*>>()], + actual_data: ::core::mem::MaybeUninit<[u8; ::core::mem::size_of::<#internal_ident<#(#generic_args),*>>()]>, _alignment: [#internal_ident<#(#generic_args),*>; 0], #(#fields),* } From 79abb08555daf29372f540222af6df399f6f0457 Mon Sep 17 00:00:00 2001 From: joshua-maros <60271685+joshua-maros@users.noreply.github.com> Date: Tue, 13 Jun 2023 21:06:21 -0500 Subject: [PATCH 7/8] Cleanup --- README.md | 4 ++++ examples/Cargo.toml | 4 ++-- examples/src/fail_tests/auto_covariant.stderr | 7 ++++++- examples/src/ok_tests.rs | 10 ++++++++-- ouroboros/Cargo.toml | 4 ++-- ouroboros/src/lib.rs | 2 +- ouroboros_macro/Cargo.toml | 2 +- ouroboros_macro/src/generate/drop.rs | 5 +---- ouroboros_macro/src/info_structures.rs | 14 +++++++------- 9 files changed, 32 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 8e5af71..77a90cf 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,10 @@ Dual licensed under MIT / Apache 2.0. While this crate is `no_std` compatible, it still requires the `alloc` crate. Version notes: +- Version `0.17.0` fixed a potential soundness issue, but removed support for + template parameters in the process. Lifetime parameters are still supported. + As of 2023-06-13, the compiler is practically sound with 0.16 but this may + stop being the case at any time and without warning. - Version `0.13.0` and later contain checks for additional situations which cause undefined behavior if not caught. - Version `0.11.0` and later place restrictions on derive macros, earlier diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 8243ddf..9f5739e 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ouroboros_examples" -version = "0.16.0" +version = "0.17.0" authors = ["Joshua Maros "] edition = "2018" license = "MIT OR Apache-2.0" @@ -21,7 +21,7 @@ std = [] __tokio = ["tokio", "std"] [dependencies] -ouroboros = { version = "0.16.0", path = "../ouroboros" } +ouroboros = { version = "0.17.0", path = "../ouroboros" } tokio = { version = "1.27.0", features = [ "macros", "rt" ], optional = true } [dev-dependencies] diff --git a/examples/src/fail_tests/auto_covariant.stderr b/examples/src/fail_tests/auto_covariant.stderr index 66b8ecf..54f2ae2 100644 --- a/examples/src/fail_tests/auto_covariant.stderr +++ b/examples/src/fail_tests/auto_covariant.stderr @@ -1,6 +1,11 @@ error: Ouroboros cannot automatically determine if this type is covariant. - If it is covariant, it should be legal to convert any instance of that type to an instance of that type where all usages of 'this are replaced with a smaller lifetime. For example, Box<&'this i32> is covariant because it is legal to use it as a Box<&'a i32> where 'this: 'a. In contrast, Fn(&'this i32) cannot be used as Fn(&'a i32). + As an example, a Box<&'this ()> is covariant because it can be used as a + Box<&'smaller ()> for any lifetime smaller than 'this. In contrast, + a Fn(&'this ()) is not covariant because it cannot be used as a + Fn(&'smaller ()). In general, values that are safe to use with smaller + lifetimes than they were defined with are covariant, breaking this + guarantee means the value is not covariant. To resolve this error, add #[covariant] or #[not_covariant] to the field. --> src/fail_tests/auto_covariant.rs:11:12 diff --git a/examples/src/ok_tests.rs b/examples/src/ok_tests.rs index 7a08614..78a04cb 100644 --- a/examples/src/ok_tests.rs +++ b/examples/src/ok_tests.rs @@ -1,4 +1,4 @@ -use alloc::boxed::Box; +use alloc::{boxed::Box, borrow::ToOwned}; use core::fmt::Debug; use ouroboros::self_referencing; @@ -31,7 +31,7 @@ struct ChainedAndUndocumented { data: i32, #[borrows(data)] ref1: &'this i32, - #[borrows(data)] + #[borrows(ref1)] ref2: &'this &'this i32, } @@ -245,6 +245,12 @@ fn single_lifetime() { #[borrows(external)] internal: &'this &'a str, } + + let external = "Hello world!".to_owned(); + let instance = Struct::new(&external, |field_ref| field_ref); + drop(instance.borrow_external()); + drop(instance.borrow_internal()); + drop(instance); } #[test] diff --git a/ouroboros/Cargo.toml b/ouroboros/Cargo.toml index 3c256b4..83845c5 100644 --- a/ouroboros/Cargo.toml +++ b/ouroboros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ouroboros" -version = "0.16.0" +version = "0.17.0" authors = ["Joshua Maros "] edition = "2018" license = "MIT OR Apache-2.0" @@ -11,7 +11,7 @@ repository = "https://github.com/joshua-maros/ouroboros" [dependencies] aliasable = "0.1.3" -ouroboros_macro = { version = "0.16.0", path = "../ouroboros_macro" } +ouroboros_macro = { version = "0.17.0", path = "../ouroboros_macro" } static_assertions = "1.1.0" [features] diff --git a/ouroboros/src/lib.rs b/ouroboros/src/lib.rs index 13870da..db6d5c5 100644 --- a/ouroboros/src/lib.rs +++ b/ouroboros/src/lib.rs @@ -123,7 +123,7 @@ /// immutable: i32, /// mutable: i32, /// #[borrows(immutable, mut mutable)] -/// #[covariant] +/// #[not_covariant] /// complex_data: ComplexData<'this, 'this>, /// } /// diff --git a/ouroboros_macro/Cargo.toml b/ouroboros_macro/Cargo.toml index 5b2a56b..3d501b6 100644 --- a/ouroboros_macro/Cargo.toml +++ b/ouroboros_macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ouroboros_macro" -version = "0.16.0" +version = "0.17.0" authors = ["Joshua Maros "] edition = "2018" license = "MIT OR Apache-2.0" diff --git a/ouroboros_macro/src/generate/drop.rs b/ouroboros_macro/src/generate/drop.rs index a78d5e1..1cfb7f2 100644 --- a/ouroboros_macro/src/generate/drop.rs +++ b/ouroboros_macro/src/generate/drop.rs @@ -1,7 +1,4 @@ -use crate::{ - info_structures::StructInfo, - utils::{self, replace_this_with_lifetime}, -}; +use crate::info_structures::StructInfo; use proc_macro2::TokenStream; use quote::quote; use syn::Error; diff --git a/ouroboros_macro/src/info_structures.rs b/ouroboros_macro/src/info_structures.rs index f3e4a54..7e7fd5c 100644 --- a/ouroboros_macro/src/info_structures.rs +++ b/ouroboros_macro/src/info_structures.rs @@ -13,13 +13,13 @@ pub struct Options { } impl Options { - pub fn documentation_to_tokens(&self, documentation: &str) -> TokenStream { - if self.do_no_doc { - quote! { #[doc(hidden)] } - } else { - quote! { #[doc=#documentation] } - } - } + // pub fn documentation_to_tokens(&self, documentation: &str) -> TokenStream { + // if self.do_no_doc { + // quote! { #[doc(hidden)] } + // } else { + // quote! { #[doc=#documentation] } + // } + // } } #[derive(Clone, Copy, PartialEq)] From 80b3e760a767a2525dfa79f17bdeaf284cd4485a Mon Sep 17 00:00:00 2001 From: joshua-maros <60271685+joshua-maros@users.noreply.github.com> Date: Wed, 14 Jun 2023 18:29:54 -0500 Subject: [PATCH 8/8] Consistent tense --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 77a90cf..c9763a3 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Dual licensed under MIT / Apache 2.0. While this crate is `no_std` compatible, it still requires the `alloc` crate. Version notes: -- Version `0.17.0` fixed a potential soundness issue, but removed support for +- Version `0.17.0` fixes a potential soundness issue, but removes support for template parameters in the process. Lifetime parameters are still supported. As of 2023-06-13, the compiler is practically sound with 0.16 but this may stop being the case at any time and without warning.