diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/codegen/mod.rs | 27 | ||||
-rw-r--r-- | src/codegen/postprocessing.rs | 227 | ||||
-rw-r--r-- | src/lib.rs | 6 | ||||
-rw-r--r-- | src/options.rs | 11 |
4 files changed, 141 insertions, 130 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index bc2c9fe2..5660b126 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -837,9 +837,34 @@ impl CodeGenerator for Type { } // If this is a known named type, disallow generating anything - // for it too. + // for it too. If size_t -> usize conversions are enabled, we + // need to check that these conversions are permissible, but + // nothing needs to be generated, still. let spelling = self.name().expect("Unnamed alias?"); if utils::type_from_named(ctx, spelling).is_some() { + if let "size_t" | "ssize_t" = spelling { + let layout = inner_item + .kind() + .expect_type() + .layout(ctx) + .expect("No layout?"); + assert_eq!( + layout.size, + ctx.target_pointer_size(), + "Target platform requires `--no-size_t-is-usize`. The size of `{}` ({}) does not match the target pointer size ({})", + spelling, + layout.size, + ctx.target_pointer_size(), + ); + assert_eq!( + layout.align, + ctx.target_pointer_size(), + "Target platform requires `--no-size_t-is-usize`. The alignment of `{}` ({}) does not match the target pointer size ({})", + spelling, + layout.align, + ctx.target_pointer_size(), + ); + } return; } diff --git a/src/codegen/postprocessing.rs b/src/codegen/postprocessing.rs index 72832298..6d935a61 100644 --- a/src/codegen/postprocessing.rs +++ b/src/codegen/postprocessing.rs @@ -4,145 +4,126 @@ use syn::Item; use crate::BindgenOptions; -macro_rules! decl_postprocessing { - ($($ty:ty),*) => { - pub(crate) fn postprocessing( - items: Vec<TokenStream>, - options: &BindgenOptions, - ) -> TokenStream { - // Whether any of the enabled options requires `syn`. - let require_syn = $(<$ty as PostProcessing>::should_run(options))||*; - - if !require_syn { - return items.into_iter().collect(); - } - - let module_wrapped_tokens = - quote!(mod wrapper_for_sorting_hack { #( #items )* }); - - // This syn business is a hack, for now. This means that we are re-parsing already - // generated code using `syn` (as opposed to `quote`) because `syn` provides us more - // control over the elements. - // One caveat is that some of the items coming from `quote`d output might have - // multiple items within them. Hence, we have to wrap the incoming in a `mod`. - // The two `unwrap`s here are deliberate because - // The first one won't panic because we build the `mod` and know it is there - // The second one won't panic because we know original output has something in - // it already. - let mut items = - syn::parse2::<syn::ItemMod>(module_wrapped_tokens) - .unwrap() - .content - .unwrap() - .1; - - $(if <$ty as PostProcessing>::should_run(options) { - <$ty as PostProcessing>::run(&mut items); - })* - - let synful_items = items - .into_iter() - .map(|item| item.into_token_stream()); +struct PostProcessingPass { + should_run: fn(&BindgenOptions) -> bool, + run: fn(&mut Vec<Item>), +} - quote! { #( #synful_items )* } +// TODO: This can be a const fn when mutable references are allowed in const +// context. +macro_rules! pass { + ($pass:ident) => { + PostProcessingPass { + should_run: |options| options.$pass, + run: $pass, } }; } -decl_postprocessing! { - MergeExternBlocks, - SortSemantically -} - -trait PostProcessing { - fn should_run(options: &BindgenOptions) -> bool; - - fn run(items: &mut Vec<Item>); -} - -struct SortSemantically; +static PASSES: [PostProcessingPass; 2] = + [pass!(merge_extern_blocks), pass!(sort_semantically)]; -impl PostProcessing for SortSemantically { - #[inline] - fn should_run(options: &BindgenOptions) -> bool { - options.sort_semantically +pub(crate) fn postprocessing( + items: Vec<TokenStream>, + options: &BindgenOptions, +) -> TokenStream { + let require_syn = PASSES.iter().any(|pass| (pass.should_run)(options)); + if !require_syn { + return items.into_iter().collect(); } - - fn run(items: &mut Vec<Item>) { - items.sort_by_key(|item| match item { - Item::Type(_) => 0, - Item::Struct(_) => 1, - Item::Const(_) => 2, - Item::Fn(_) => 3, - Item::Enum(_) => 4, - Item::Union(_) => 5, - Item::Static(_) => 6, - Item::Trait(_) => 7, - Item::TraitAlias(_) => 8, - Item::Impl(_) => 9, - Item::Mod(_) => 10, - Item::Use(_) => 11, - Item::Verbatim(_) => 12, - Item::ExternCrate(_) => 13, - Item::ForeignMod(_) => 14, - Item::Macro(_) => 15, - Item::Macro2(_) => 16, - _ => 18, - }); + let module_wrapped_tokens = + quote!(mod wrapper_for_sorting_hack { #( #items )* }); + + // This syn business is a hack, for now. This means that we are re-parsing already + // generated code using `syn` (as opposed to `quote`) because `syn` provides us more + // control over the elements. + // One caveat is that some of the items coming from `quote`d output might have + // multiple items within them. Hence, we have to wrap the incoming in a `mod`. + // The two `unwrap`s here are deliberate because + // The first one won't panic because we build the `mod` and know it is there + // The second one won't panic because we know original output has something in + // it already. + let mut items = syn::parse2::<syn::ItemMod>(module_wrapped_tokens) + .unwrap() + .content + .unwrap() + .1; + + for pass in PASSES.iter() { + if (pass.should_run)(options) { + (pass.run)(&mut items); + } } -} -struct MergeExternBlocks; + let synful_items = items.into_iter().map(|item| item.into_token_stream()); -impl PostProcessing for MergeExternBlocks { - #[inline] - fn should_run(options: &BindgenOptions) -> bool { - options.merge_extern_blocks - } + quote! { #( #synful_items )* } +} - fn run(items: &mut Vec<Item>) { - // Keep all the extern blocks in a different `Vec` for faster search. - let mut foreign_mods = Vec::<syn::ItemForeignMod>::new(); +fn sort_semantically(items: &mut Vec<Item>) { + items.sort_by_key(|item| match item { + Item::Type(_) => 0, + Item::Struct(_) => 1, + Item::Const(_) => 2, + Item::Fn(_) => 3, + Item::Enum(_) => 4, + Item::Union(_) => 5, + Item::Static(_) => 6, + Item::Trait(_) => 7, + Item::TraitAlias(_) => 8, + Item::Impl(_) => 9, + Item::Mod(_) => 10, + Item::Use(_) => 11, + Item::Verbatim(_) => 12, + Item::ExternCrate(_) => 13, + Item::ForeignMod(_) => 14, + Item::Macro(_) => 15, + Item::Macro2(_) => 16, + _ => 18, + }); +} - for item in std::mem::take(items) { - match item { - Item::ForeignMod(syn::ItemForeignMod { - attrs, - abi, - brace_token, - items: foreign_items, - }) => { - let mut exists = false; - for foreign_mod in &mut foreign_mods { - // Check if there is a extern block with the same ABI and - // attributes. - if foreign_mod.attrs == attrs && foreign_mod.abi == abi - { - // Merge the items of the two blocks. - foreign_mod.items.extend_from_slice(&foreign_items); - exists = true; - break; - } - } - // If no existing extern block had the same ABI and attributes, store - // it. - if !exists { - foreign_mods.push(syn::ItemForeignMod { - attrs, - abi, - brace_token, - items: foreign_items, - }); +fn merge_extern_blocks(items: &mut Vec<Item>) { + // Keep all the extern blocks in a different `Vec` for faster search. + let mut foreign_mods = Vec::<syn::ItemForeignMod>::new(); + + for item in std::mem::take(items) { + match item { + Item::ForeignMod(syn::ItemForeignMod { + attrs, + abi, + brace_token, + items: foreign_items, + }) => { + let mut exists = false; + for foreign_mod in &mut foreign_mods { + // Check if there is a extern block with the same ABI and + // attributes. + if foreign_mod.attrs == attrs && foreign_mod.abi == abi { + // Merge the items of the two blocks. + foreign_mod.items.extend_from_slice(&foreign_items); + exists = true; + break; } } - // If the item is not an extern block, we don't have to do anything. - _ => items.push(item), + // If no existing extern block had the same ABI and attributes, store + // it. + if !exists { + foreign_mods.push(syn::ItemForeignMod { + attrs, + abi, + brace_token, + items: foreign_items, + }); + } } + // If the item is not an extern block, we don't have to do anything. + _ => items.push(item), } + } - // Move all the extern blocks alongiside the rest of the items. - for foreign_mod in foreign_mods { - items.push(Item::ForeignMod(foreign_mod)); - } + // Move all the extern blocks alongside the rest of the items. + for foreign_mod in foreign_mods { + items.push(Item::ForeignMod(foreign_mod)); } } @@ -563,8 +563,8 @@ impl Builder { output_vector.push("--no-record-matches".into()); } - if self.options.size_t_is_usize { - output_vector.push("--size_t-is-usize".into()); + if !self.options.size_t_is_usize { + output_vector.push("--no-size_t-is-usize".into()); } if !self.options.rustfmt_bindings { @@ -2247,7 +2247,7 @@ impl Default for BindgenOptions { time_phases: false, record_matches: true, rustfmt_bindings: true, - size_t_is_usize: false, + size_t_is_usize: true, rustfmt_configuration_file: None, no_partialeq_types: Default::default(), no_copy_types: Default::default(), diff --git a/src/options.rs b/src/options.rs index f707ab9b..29edb78b 100644 --- a/src/options.rs +++ b/src/options.rs @@ -465,7 +465,12 @@ where ), Arg::new("size_t-is-usize") .long("size_t-is-usize") - .help("Translate size_t to usize."), + .help("Ignored - this is enabled by default.") + .hidden(true), + Arg::with_name("no-size_t-is-usize") + .long("no-size_t-is-usize") + .help("Do not bind size_t as usize (useful on platforms \ + where those types are incompatible)."), Arg::new("no-rustfmt-bindings") .long("no-rustfmt-bindings") .help("Do not format the generated bindings with rustfmt."), @@ -975,8 +980,8 @@ where builder = builder.record_matches(false); } - if matches.is_present("size_t-is-usize") { - builder = builder.size_t_is_usize(true); + if matches.is_present("no-size_t-is-usize") { + builder = builder.size_t_is_usize(false); } let no_rustfmt_bindings = matches.is_present("no-rustfmt-bindings"); |