From b073b3b77b3d00c13b37fb0474390b52aa9441e5 Mon Sep 17 00:00:00 2001 From: Douglas Creager Date: Mon, 21 Jun 2021 10:18:53 -0400 Subject: [PATCH 1/2] Follow multiple transparent links in Option layout Option can take advantage of layout optimizations when its inner type is nullable or zeroable. Before, we were only looking at the Option's direct generic parameter when deciding whether we could use this optimization. But the layout optimization "propagates through" typedefs and transparent structs. We now repeatedly follow these type aliases until we reach a non-aliased type, and only then check whether the type is nullable/zeroable. --- src/bindgen/ir/function.rs | 11 +++-- src/bindgen/ir/global.rs | 9 +++- src/bindgen/ir/structure.rs | 9 +++- src/bindgen/ir/ty.rs | 32 ++++++++++-- src/bindgen/ir/typedef.rs | 10 +++- src/bindgen/ir/union.rs | 9 +++- src/bindgen/library.rs | 14 ++++-- src/bindgen/mod.rs | 1 + src/bindgen/transparent_types.rs | 49 +++++++++++++++++++ .../exclude_generic_monomorph.both.c | 2 +- .../exclude_generic_monomorph.both.compat.c | 2 +- .../expectations/exclude_generic_monomorph.c | 2 +- .../exclude_generic_monomorph.compat.c | 2 +- .../exclude_generic_monomorph.cpp | 2 +- .../exclude_generic_monomorph.pyx | 2 +- .../exclude_generic_monomorph.tag.c | 2 +- .../exclude_generic_monomorph.tag.compat.c | 2 +- .../exclude_generic_monomorph.tag.pyx | 2 +- tests/expectations/nested_nonnull.both.c | 21 ++++++++ .../expectations/nested_nonnull.both.compat.c | 29 +++++++++++ tests/expectations/nested_nonnull.c | 20 ++++++++ tests/expectations/nested_nonnull.compat.c | 28 +++++++++++ tests/expectations/nested_nonnull.cpp | 26 ++++++++++ tests/expectations/nested_nonnull.pyx | 21 ++++++++ tests/expectations/nested_nonnull.tag.c | 21 ++++++++ .../expectations/nested_nonnull.tag.compat.c | 29 +++++++++++ tests/expectations/nested_nonnull.tag.pyx | 21 ++++++++ tests/expectations/nested_nonzero.both.c | 13 +++++ .../expectations/nested_nonzero.both.compat.c | 21 ++++++++ tests/expectations/nested_nonzero.c | 13 +++++ tests/expectations/nested_nonzero.compat.c | 21 ++++++++ tests/expectations/nested_nonzero.cpp | 21 ++++++++ tests/expectations/nested_nonzero.pyx | 15 ++++++ tests/expectations/nested_nonzero.tag.c | 13 +++++ .../expectations/nested_nonzero.tag.compat.c | 21 ++++++++ tests/expectations/nested_nonzero.tag.pyx | 15 ++++++ tests/rust/nested_nonnull.rs | 21 ++++++++ tests/rust/nested_nonzero.rs | 16 ++++++ 38 files changed, 538 insertions(+), 30 deletions(-) create mode 100644 src/bindgen/transparent_types.rs create mode 100644 tests/expectations/nested_nonnull.both.c create mode 100644 tests/expectations/nested_nonnull.both.compat.c create mode 100644 tests/expectations/nested_nonnull.c create mode 100644 tests/expectations/nested_nonnull.compat.c create mode 100644 tests/expectations/nested_nonnull.cpp create mode 100644 tests/expectations/nested_nonnull.pyx create mode 100644 tests/expectations/nested_nonnull.tag.c create mode 100644 tests/expectations/nested_nonnull.tag.compat.c create mode 100644 tests/expectations/nested_nonnull.tag.pyx create mode 100644 tests/expectations/nested_nonzero.both.c create mode 100644 tests/expectations/nested_nonzero.both.compat.c create mode 100644 tests/expectations/nested_nonzero.c create mode 100644 tests/expectations/nested_nonzero.compat.c create mode 100644 tests/expectations/nested_nonzero.cpp create mode 100644 tests/expectations/nested_nonzero.pyx create mode 100644 tests/expectations/nested_nonzero.tag.c create mode 100644 tests/expectations/nested_nonzero.tag.compat.c create mode 100644 tests/expectations/nested_nonzero.tag.pyx create mode 100644 tests/rust/nested_nonnull.rs create mode 100644 tests/rust/nested_nonzero.rs diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index 6d310aaa8..dea5dd1fb 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -17,6 +17,7 @@ use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::rename::{IdentifierType, RenameRule}; use crate::bindgen::reserved; +use crate::bindgen::transparent_types::TransparentTypes; use crate::bindgen::utilities::IterHelpers; use crate::bindgen::writer::{Source, SourceWriter}; @@ -127,10 +128,14 @@ impl Function { &self.path } - pub fn simplify_standard_types(&mut self, config: &Config) { - self.ret.simplify_standard_types(config); + pub fn simplify_standard_types( + &mut self, + config: &Config, + transparent_types: &TransparentTypes, + ) { + self.ret.simplify_standard_types(config, transparent_types); for arg in &mut self.args { - arg.ty.simplify_standard_types(config); + arg.ty.simplify_standard_types(config, transparent_types); } } diff --git a/src/bindgen/ir/global.rs b/src/bindgen/ir/global.rs index a9d989df8..047f6b96c 100644 --- a/src/bindgen/ir/global.rs +++ b/src/bindgen/ir/global.rs @@ -10,6 +10,7 @@ use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{AnnotationSet, Cfg, Documentation, Item, ItemContainer, Path, Type}; use crate::bindgen::library::Library; +use crate::bindgen::transparent_types::TransparentTypes; use crate::bindgen::writer::{Source, SourceWriter}; #[derive(Debug, Clone)] @@ -61,8 +62,12 @@ impl Static { } } - pub fn simplify_standard_types(&mut self, config: &Config) { - self.ty.simplify_standard_types(config); + pub fn simplify_standard_types( + &mut self, + config: &Config, + transparent_types: &TransparentTypes, + ) { + self.ty.simplify_standard_types(config, transparent_types); } } diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 206f04c8e..23f5465e7 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -16,6 +16,7 @@ use crate::bindgen::mangle; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::rename::{IdentifierType, RenameRule}; use crate::bindgen::reserved; +use crate::bindgen::transparent_types::TransparentTypes; use crate::bindgen::utilities::IterHelpers; use crate::bindgen::writer::{ListType, Source, SourceWriter}; @@ -142,9 +143,13 @@ impl Struct { } } - pub fn simplify_standard_types(&mut self, config: &Config) { + pub fn simplify_standard_types( + &mut self, + config: &Config, + transparent_types: &TransparentTypes, + ) { for field in &mut self.fields { - field.ty.simplify_standard_types(config); + field.ty.simplify_standard_types(config, transparent_types); } } diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index e4452f391..7bc0a6430 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -12,6 +12,7 @@ use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{GenericParams, GenericPath, Path}; use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::transparent_types::TransparentTypes; use crate::bindgen::utilities::IterHelpers; use crate::bindgen::writer::{Source, SourceWriter}; @@ -588,7 +589,11 @@ impl Type { })) } - fn simplified_type(&self, config: &Config) -> Option { + fn simplified_type( + &self, + config: &Config, + transparent_types: &TransparentTypes, + ) -> Option { let path = match *self { Type::Path(ref p) => p, _ => return None, @@ -603,12 +608,25 @@ impl Type { } let unsimplified_generic = &path.generics()[0]; - let generic = match unsimplified_generic.simplified_type(config) { + let mut generic = match unsimplified_generic.simplified_type(config, transparent_types) { Some(generic) => Cow::Owned(generic), None => Cow::Borrowed(unsimplified_generic), }; match path.name() { "Option" => { + // Repeatedly follow any typedefs or transparent structs until we reach a type that + // has its own "real" type in C/C++. + while let Some(transparent) = transparent_types.is_transparent(&generic) { + // Make sure to do another round of simplifying each time we follow a typedef + // or transparent struct link. + generic = match transparent.simplified_type(config, transparent_types) { + Some(generic) => Cow::Owned(generic), + None => Cow::Owned(transparent), + }; + } + + // Once we've found the base type for the Option's generic, see if we can take + // advantage of any nullable/zeroable layout optimizations. if let Some(nullable) = generic.make_nullable() { return Some(nullable); } @@ -637,9 +655,13 @@ impl Type { } } - pub fn simplify_standard_types(&mut self, config: &Config) { - self.visit_types(|ty| ty.simplify_standard_types(config)); - if let Some(ty) = self.simplified_type(config) { + pub fn simplify_standard_types( + &mut self, + config: &Config, + transparent_types: &TransparentTypes, + ) { + self.visit_types(|ty| ty.simplify_standard_types(config, transparent_types)); + if let Some(ty) = self.simplified_type(config, transparent_types) { *self = ty; } } diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index d7e02a344..43838c223 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -15,6 +15,7 @@ use crate::bindgen::ir::{ use crate::bindgen::library::Library; use crate::bindgen::mangle; use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::transparent_types::TransparentTypes; use crate::bindgen::writer::{Source, SourceWriter}; /// A type alias that is represented as a C typedef @@ -66,8 +67,13 @@ impl Typedef { } } - pub fn simplify_standard_types(&mut self, config: &Config) { - self.aliased.simplify_standard_types(config); + pub fn simplify_standard_types( + &mut self, + config: &Config, + transparent_types: &TransparentTypes, + ) { + self.aliased + .simplify_standard_types(config, transparent_types); } pub fn transfer_annotations(&mut self, out: &mut HashMap) { diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index 6254a99b6..efa2a5772 100644 --- a/src/bindgen/ir/union.rs +++ b/src/bindgen/ir/union.rs @@ -15,6 +15,7 @@ use crate::bindgen::library::Library; use crate::bindgen::mangle; use crate::bindgen::monomorph::Monomorphs; use crate::bindgen::rename::{IdentifierType, RenameRule}; +use crate::bindgen::transparent_types::TransparentTypes; use crate::bindgen::utilities::IterHelpers; use crate::bindgen::writer::{ListType, Source, SourceWriter}; @@ -95,9 +96,13 @@ impl Union { } } - pub fn simplify_standard_types(&mut self, config: &Config) { + pub fn simplify_standard_types( + &mut self, + config: &Config, + transparent_types: &TransparentTypes, + ) { for field in &mut self.fields { - field.ty.simplify_standard_types(config); + field.ty.simplify_standard_types(config, transparent_types); } } diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index b1f9eb457..8cbceb2d6 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -12,6 +12,7 @@ use crate::bindgen::error::Error; use crate::bindgen::ir::{Constant, Enum, Function, Item, ItemContainer, ItemMap}; use crate::bindgen::ir::{OpaqueItem, Path, Static, Struct, Typedef, Union}; use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::transparent_types::TransparentTypes; use crate::bindgen::ItemType; #[derive(Debug, Clone)] @@ -358,21 +359,24 @@ impl Library { fn simplify_standard_types(&mut self) { let config = &self.config; + let mut transparent_types = TransparentTypes::default(); + transparent_types.add_structs(&self.structs); + transparent_types.add_typedefs(&self.typedefs); self.structs.for_all_items_mut(|x| { - x.simplify_standard_types(config); + x.simplify_standard_types(config, &transparent_types); }); self.unions.for_all_items_mut(|x| { - x.simplify_standard_types(config); + x.simplify_standard_types(config, &transparent_types); }); self.globals.for_all_items_mut(|x| { - x.simplify_standard_types(config); + x.simplify_standard_types(config, &transparent_types); }); self.typedefs.for_all_items_mut(|x| { - x.simplify_standard_types(config); + x.simplify_standard_types(config, &transparent_types); }); for x in &mut self.functions { - x.simplify_standard_types(config); + x.simplify_standard_types(config, &transparent_types); } } diff --git a/src/bindgen/mod.rs b/src/bindgen/mod.rs index d0789da2e..d535986c8 100644 --- a/src/bindgen/mod.rs +++ b/src/bindgen/mod.rs @@ -52,6 +52,7 @@ mod monomorph; mod parser; mod rename; mod reserved; +mod transparent_types; mod utilities; mod writer; diff --git a/src/bindgen/transparent_types.rs b/src/bindgen/transparent_types.rs new file mode 100644 index 000000000..3115a9559 --- /dev/null +++ b/src/bindgen/transparent_types.rs @@ -0,0 +1,49 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use std::collections::HashMap; + +use crate::bindgen::ir::{GenericParams, ItemMap, Path, Struct, Type, Typedef}; + +/// Keeps track of named types that have the same underlying representation as some other type. +/// This happens via `#[repr(transparent)]` structs and via typedefs. +#[derive(Default)] +pub struct TransparentTypes { + transparent: HashMap, +} + +impl TransparentTypes { + pub fn add_structs(&mut self, structs: &ItemMap) { + structs.for_all_items(|s| { + if s.is_transparent { + self.transparent.insert( + s.path.clone(), + (s.fields[0].ty.clone(), s.generic_params.clone()), + ); + } + }); + } + + pub fn add_typedefs(&mut self, structs: &ItemMap) { + structs.for_all_items(|t| { + self.transparent.insert( + t.path.clone(), + (t.aliased.clone(), t.generic_params.clone()), + ); + }); + } + + pub fn is_transparent(&self, ty: &Type) -> Option { + let generic_path = match ty { + Type::Path(p) => p, + _ => return None, + }; + let (resolved, generic_params) = self.transparent.get(generic_path.path())?; + let mappings = generic_params + .iter() + .zip(generic_path.generics()) + .collect::>(); + Some(resolved.specialize(&mappings)) + } +} diff --git a/tests/expectations/exclude_generic_monomorph.both.c b/tests/expectations/exclude_generic_monomorph.both.c index 09b5455dd..b641f75f1 100644 --- a/tests/expectations/exclude_generic_monomorph.both.c +++ b/tests/expectations/exclude_generic_monomorph.both.c @@ -22,7 +22,7 @@ ctypedef uint64_t Option_Foo #include typedef struct Bar { - Option_Foo foo; + uint64_t foo; } Bar; void root(struct Bar f); diff --git a/tests/expectations/exclude_generic_monomorph.both.compat.c b/tests/expectations/exclude_generic_monomorph.both.compat.c index 3c1037efc..dc78696f3 100644 --- a/tests/expectations/exclude_generic_monomorph.both.compat.c +++ b/tests/expectations/exclude_generic_monomorph.both.compat.c @@ -22,7 +22,7 @@ ctypedef uint64_t Option_Foo #include typedef struct Bar { - Option_Foo foo; + uint64_t foo; } Bar; #ifdef __cplusplus diff --git a/tests/expectations/exclude_generic_monomorph.c b/tests/expectations/exclude_generic_monomorph.c index a593dd7ab..bcd03a7e8 100644 --- a/tests/expectations/exclude_generic_monomorph.c +++ b/tests/expectations/exclude_generic_monomorph.c @@ -22,7 +22,7 @@ ctypedef uint64_t Option_Foo #include typedef struct { - Option_Foo foo; + uint64_t foo; } Bar; void root(Bar f); diff --git a/tests/expectations/exclude_generic_monomorph.compat.c b/tests/expectations/exclude_generic_monomorph.compat.c index 5c10d43a1..a769cd0db 100644 --- a/tests/expectations/exclude_generic_monomorph.compat.c +++ b/tests/expectations/exclude_generic_monomorph.compat.c @@ -22,7 +22,7 @@ ctypedef uint64_t Option_Foo #include typedef struct { - Option_Foo foo; + uint64_t foo; } Bar; #ifdef __cplusplus diff --git a/tests/expectations/exclude_generic_monomorph.cpp b/tests/expectations/exclude_generic_monomorph.cpp index 09b5455dd..b641f75f1 100644 --- a/tests/expectations/exclude_generic_monomorph.cpp +++ b/tests/expectations/exclude_generic_monomorph.cpp @@ -22,7 +22,7 @@ ctypedef uint64_t Option_Foo #include typedef struct Bar { - Option_Foo foo; + uint64_t foo; } Bar; void root(struct Bar f); diff --git a/tests/expectations/exclude_generic_monomorph.pyx b/tests/expectations/exclude_generic_monomorph.pyx index 48cd1e242..b645aa72f 100644 --- a/tests/expectations/exclude_generic_monomorph.pyx +++ b/tests/expectations/exclude_generic_monomorph.pyx @@ -25,6 +25,6 @@ cdef extern from *: cdef extern from *: ctypedef struct Bar: - Option_Foo foo; + uint64_t foo; void root(Bar f); diff --git a/tests/expectations/exclude_generic_monomorph.tag.c b/tests/expectations/exclude_generic_monomorph.tag.c index 116a170fc..a50286339 100644 --- a/tests/expectations/exclude_generic_monomorph.tag.c +++ b/tests/expectations/exclude_generic_monomorph.tag.c @@ -22,7 +22,7 @@ ctypedef uint64_t Option_Foo #include struct Bar { - Option_Foo foo; + uint64_t foo; }; void root(struct Bar f); diff --git a/tests/expectations/exclude_generic_monomorph.tag.compat.c b/tests/expectations/exclude_generic_monomorph.tag.compat.c index fa8e3a101..9092d856b 100644 --- a/tests/expectations/exclude_generic_monomorph.tag.compat.c +++ b/tests/expectations/exclude_generic_monomorph.tag.compat.c @@ -22,7 +22,7 @@ ctypedef uint64_t Option_Foo #include struct Bar { - Option_Foo foo; + uint64_t foo; }; #ifdef __cplusplus diff --git a/tests/expectations/exclude_generic_monomorph.tag.pyx b/tests/expectations/exclude_generic_monomorph.tag.pyx index 934536f40..c8cdf1fa3 100644 --- a/tests/expectations/exclude_generic_monomorph.tag.pyx +++ b/tests/expectations/exclude_generic_monomorph.tag.pyx @@ -25,6 +25,6 @@ cdef extern from *: cdef extern from *: cdef struct Bar: - Option_Foo foo; + uint64_t foo; void root(Bar f); diff --git a/tests/expectations/nested_nonnull.both.c b/tests/expectations/nested_nonnull.both.c new file mode 100644 index 000000000..2bd11c741 --- /dev/null +++ b/tests/expectations/nested_nonnull.both.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +typedef int32_t (*DoFn)(int32_t x, int32_t y); + +typedef struct StructWithOptionalFunctionPointer { + DoFn func; + int32_t (*maybe_func)(int32_t x, int32_t y); +} StructWithOptionalFunctionPointer; + +typedef uint32_t *NonNullAlias_u32; + +typedef struct StructWithOptionalNonNullPointer { + NonNullAlias_u32 data; + uint32_t *maybe_data; +} StructWithOptionalNonNullPointer; + +void root(struct StructWithOptionalFunctionPointer swofp, + struct StructWithOptionalNonNullPointer swonnp); diff --git a/tests/expectations/nested_nonnull.both.compat.c b/tests/expectations/nested_nonnull.both.compat.c new file mode 100644 index 000000000..e268acfa5 --- /dev/null +++ b/tests/expectations/nested_nonnull.both.compat.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include + +typedef int32_t (*DoFn)(int32_t x, int32_t y); + +typedef struct StructWithOptionalFunctionPointer { + DoFn func; + int32_t (*maybe_func)(int32_t x, int32_t y); +} StructWithOptionalFunctionPointer; + +typedef uint32_t *NonNullAlias_u32; + +typedef struct StructWithOptionalNonNullPointer { + NonNullAlias_u32 data; + uint32_t *maybe_data; +} StructWithOptionalNonNullPointer; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root(struct StructWithOptionalFunctionPointer swofp, + struct StructWithOptionalNonNullPointer swonnp); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/nested_nonnull.c b/tests/expectations/nested_nonnull.c new file mode 100644 index 000000000..bbc953016 --- /dev/null +++ b/tests/expectations/nested_nonnull.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +typedef int32_t (*DoFn)(int32_t x, int32_t y); + +typedef struct { + DoFn func; + int32_t (*maybe_func)(int32_t x, int32_t y); +} StructWithOptionalFunctionPointer; + +typedef uint32_t *NonNullAlias_u32; + +typedef struct { + NonNullAlias_u32 data; + uint32_t *maybe_data; +} StructWithOptionalNonNullPointer; + +void root(StructWithOptionalFunctionPointer swofp, StructWithOptionalNonNullPointer swonnp); diff --git a/tests/expectations/nested_nonnull.compat.c b/tests/expectations/nested_nonnull.compat.c new file mode 100644 index 000000000..1a73626ea --- /dev/null +++ b/tests/expectations/nested_nonnull.compat.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +typedef int32_t (*DoFn)(int32_t x, int32_t y); + +typedef struct { + DoFn func; + int32_t (*maybe_func)(int32_t x, int32_t y); +} StructWithOptionalFunctionPointer; + +typedef uint32_t *NonNullAlias_u32; + +typedef struct { + NonNullAlias_u32 data; + uint32_t *maybe_data; +} StructWithOptionalNonNullPointer; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root(StructWithOptionalFunctionPointer swofp, StructWithOptionalNonNullPointer swonnp); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/nested_nonnull.cpp b/tests/expectations/nested_nonnull.cpp new file mode 100644 index 000000000..0eb1c2344 --- /dev/null +++ b/tests/expectations/nested_nonnull.cpp @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include + +using DoFn = int32_t(*)(int32_t x, int32_t y); + +struct StructWithOptionalFunctionPointer { + DoFn func; + int32_t (*maybe_func)(int32_t x, int32_t y); +}; + +template +using NonNullAlias = T*; + +struct StructWithOptionalNonNullPointer { + NonNullAlias data; + uint32_t *maybe_data; +}; + +extern "C" { + +void root(StructWithOptionalFunctionPointer swofp, StructWithOptionalNonNullPointer swonnp); + +} // extern "C" diff --git a/tests/expectations/nested_nonnull.pyx b/tests/expectations/nested_nonnull.pyx new file mode 100644 index 000000000..173504f07 --- /dev/null +++ b/tests/expectations/nested_nonnull.pyx @@ -0,0 +1,21 @@ +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list + +cdef extern from *: + + ctypedef int32_t (*DoFn)(int32_t x, int32_t y); + + ctypedef struct StructWithOptionalFunctionPointer: + DoFn func; + int32_t (*maybe_func)(int32_t x, int32_t y); + + ctypedef uint32_t *NonNullAlias_u32; + + ctypedef struct StructWithOptionalNonNullPointer: + NonNullAlias_u32 data; + uint32_t *maybe_data; + + void root(StructWithOptionalFunctionPointer swofp, StructWithOptionalNonNullPointer swonnp); diff --git a/tests/expectations/nested_nonnull.tag.c b/tests/expectations/nested_nonnull.tag.c new file mode 100644 index 000000000..d69c2ebf6 --- /dev/null +++ b/tests/expectations/nested_nonnull.tag.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +typedef int32_t (*DoFn)(int32_t x, int32_t y); + +struct StructWithOptionalFunctionPointer { + DoFn func; + int32_t (*maybe_func)(int32_t x, int32_t y); +}; + +typedef uint32_t *NonNullAlias_u32; + +struct StructWithOptionalNonNullPointer { + NonNullAlias_u32 data; + uint32_t *maybe_data; +}; + +void root(struct StructWithOptionalFunctionPointer swofp, + struct StructWithOptionalNonNullPointer swonnp); diff --git a/tests/expectations/nested_nonnull.tag.compat.c b/tests/expectations/nested_nonnull.tag.compat.c new file mode 100644 index 000000000..44809c18a --- /dev/null +++ b/tests/expectations/nested_nonnull.tag.compat.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include + +typedef int32_t (*DoFn)(int32_t x, int32_t y); + +struct StructWithOptionalFunctionPointer { + DoFn func; + int32_t (*maybe_func)(int32_t x, int32_t y); +}; + +typedef uint32_t *NonNullAlias_u32; + +struct StructWithOptionalNonNullPointer { + NonNullAlias_u32 data; + uint32_t *maybe_data; +}; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root(struct StructWithOptionalFunctionPointer swofp, + struct StructWithOptionalNonNullPointer swonnp); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/nested_nonnull.tag.pyx b/tests/expectations/nested_nonnull.tag.pyx new file mode 100644 index 000000000..0c6ec1093 --- /dev/null +++ b/tests/expectations/nested_nonnull.tag.pyx @@ -0,0 +1,21 @@ +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list + +cdef extern from *: + + ctypedef int32_t (*DoFn)(int32_t x, int32_t y); + + cdef struct StructWithOptionalFunctionPointer: + DoFn func; + int32_t (*maybe_func)(int32_t x, int32_t y); + + ctypedef uint32_t *NonNullAlias_u32; + + cdef struct StructWithOptionalNonNullPointer: + NonNullAlias_u32 data; + uint32_t *maybe_data; + + void root(StructWithOptionalFunctionPointer swofp, StructWithOptionalNonNullPointer swonnp); diff --git a/tests/expectations/nested_nonzero.both.c b/tests/expectations/nested_nonzero.both.c new file mode 100644 index 000000000..13e10d4f5 --- /dev/null +++ b/tests/expectations/nested_nonzero.both.c @@ -0,0 +1,13 @@ +#include +#include +#include +#include + +typedef uint32_t Handle_File; + +typedef struct Node { + Handle_File file; + uint32_t maybe_file; +} Node; + +void root(const struct Node *node); diff --git a/tests/expectations/nested_nonzero.both.compat.c b/tests/expectations/nested_nonzero.both.compat.c new file mode 100644 index 000000000..96969d771 --- /dev/null +++ b/tests/expectations/nested_nonzero.both.compat.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +typedef uint32_t Handle_File; + +typedef struct Node { + Handle_File file; + uint32_t maybe_file; +} Node; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root(const struct Node *node); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/nested_nonzero.c b/tests/expectations/nested_nonzero.c new file mode 100644 index 000000000..b7a2ccb77 --- /dev/null +++ b/tests/expectations/nested_nonzero.c @@ -0,0 +1,13 @@ +#include +#include +#include +#include + +typedef uint32_t Handle_File; + +typedef struct { + Handle_File file; + uint32_t maybe_file; +} Node; + +void root(const Node *node); diff --git a/tests/expectations/nested_nonzero.compat.c b/tests/expectations/nested_nonzero.compat.c new file mode 100644 index 000000000..628890b68 --- /dev/null +++ b/tests/expectations/nested_nonzero.compat.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +typedef uint32_t Handle_File; + +typedef struct { + Handle_File file; + uint32_t maybe_file; +} Node; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root(const Node *node); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/nested_nonzero.cpp b/tests/expectations/nested_nonzero.cpp new file mode 100644 index 000000000..270b6507c --- /dev/null +++ b/tests/expectations/nested_nonzero.cpp @@ -0,0 +1,21 @@ +#include +#include +#include +#include +#include + +struct File; + +template +using Handle = uint32_t; + +struct Node { + Handle file; + uint32_t maybe_file; +}; + +extern "C" { + +void root(const Node *node); + +} // extern "C" diff --git a/tests/expectations/nested_nonzero.pyx b/tests/expectations/nested_nonzero.pyx new file mode 100644 index 000000000..caba1f3c0 --- /dev/null +++ b/tests/expectations/nested_nonzero.pyx @@ -0,0 +1,15 @@ +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list + +cdef extern from *: + + ctypedef uint32_t Handle_File; + + ctypedef struct Node: + Handle_File file; + uint32_t maybe_file; + + void root(const Node *node); diff --git a/tests/expectations/nested_nonzero.tag.c b/tests/expectations/nested_nonzero.tag.c new file mode 100644 index 000000000..9226df9c8 --- /dev/null +++ b/tests/expectations/nested_nonzero.tag.c @@ -0,0 +1,13 @@ +#include +#include +#include +#include + +typedef uint32_t Handle_File; + +struct Node { + Handle_File file; + uint32_t maybe_file; +}; + +void root(const struct Node *node); diff --git a/tests/expectations/nested_nonzero.tag.compat.c b/tests/expectations/nested_nonzero.tag.compat.c new file mode 100644 index 000000000..dfac1534b --- /dev/null +++ b/tests/expectations/nested_nonzero.tag.compat.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +typedef uint32_t Handle_File; + +struct Node { + Handle_File file; + uint32_t maybe_file; +}; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root(const struct Node *node); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/nested_nonzero.tag.pyx b/tests/expectations/nested_nonzero.tag.pyx new file mode 100644 index 000000000..9e80816d6 --- /dev/null +++ b/tests/expectations/nested_nonzero.tag.pyx @@ -0,0 +1,15 @@ +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list + +cdef extern from *: + + ctypedef uint32_t Handle_File; + + cdef struct Node: + Handle_File file; + uint32_t maybe_file; + + void root(const Node *node); diff --git a/tests/rust/nested_nonnull.rs b/tests/rust/nested_nonnull.rs new file mode 100644 index 000000000..ead2702a9 --- /dev/null +++ b/tests/rust/nested_nonnull.rs @@ -0,0 +1,21 @@ +type DoFn = extern "C" fn(x: i32, y: i32) -> i32; +type NonNullAlias = std::ptr::NonNull; + +#[repr(C)] +struct StructWithOptionalFunctionPointer { + func: DoFn, + maybe_func: Option, +} + +#[repr(C)] +struct StructWithOptionalNonNullPointer { + data: NonNullAlias, + maybe_data: Option>, +} + +#[no_mangle] +pub extern "C" fn root( + swofp: StructWithOptionalFunctionPointer, + swonnp: StructWithOptionalNonNullPointer, +) { +} diff --git a/tests/rust/nested_nonzero.rs b/tests/rust/nested_nonzero.rs new file mode 100644 index 000000000..ab05fc73a --- /dev/null +++ b/tests/rust/nested_nonzero.rs @@ -0,0 +1,16 @@ +#[repr(transparent)] +struct Handle { + value: std::num::NonZeroU32, + _phantom: std::marker::PhantomData, +} + +struct File; + +#[repr(C)] +struct Node { + file: Handle, + maybe_file: Option>, +} + +#[no_mangle] +pub extern "C" fn root(node: &Node) {} From 1d130f335e7bb3360599733b431b39262f65fd9b Mon Sep 17 00:00:00 2001 From: Douglas Creager Date: Tue, 22 Jun 2021 08:08:12 -0400 Subject: [PATCH 2/2] Allow path types to be nullable/zeroable As part of simplifying, we follow any typedefs or transparent structs to determine if a path type is aliased to a type that is nullable or zeroable. If so, that path type can participate in the Option layout optimization just like primitive nullable/zeroable types. --- src/bindgen/cdecl.rs | 4 +- src/bindgen/ir/enumeration.rs | 4 +- src/bindgen/ir/function.rs | 2 +- src/bindgen/ir/ty.rs | 161 +++++++++++++----- src/bindgen/mangle.rs | 6 +- src/bindgen/transparent_types.rs | 2 +- .../exclude_generic_monomorph.both.c | 4 +- .../exclude_generic_monomorph.both.compat.c | 4 +- .../expectations/exclude_generic_monomorph.c | 4 +- .../exclude_generic_monomorph.compat.c | 4 +- .../exclude_generic_monomorph.cpp | 4 +- .../exclude_generic_monomorph.pyx | 4 +- .../exclude_generic_monomorph.tag.c | 4 +- .../exclude_generic_monomorph.tag.compat.c | 4 +- .../exclude_generic_monomorph.tag.pyx | 4 +- tests/expectations/nested_nonnull.both.c | 4 +- .../expectations/nested_nonnull.both.compat.c | 4 +- tests/expectations/nested_nonnull.c | 4 +- tests/expectations/nested_nonnull.compat.c | 4 +- tests/expectations/nested_nonnull.cpp | 4 +- tests/expectations/nested_nonnull.pyx | 4 +- tests/expectations/nested_nonnull.tag.c | 4 +- .../expectations/nested_nonnull.tag.compat.c | 4 +- tests/expectations/nested_nonnull.tag.pyx | 4 +- tests/expectations/nested_nonzero.both.c | 2 +- .../expectations/nested_nonzero.both.compat.c | 2 +- tests/expectations/nested_nonzero.c | 2 +- tests/expectations/nested_nonzero.compat.c | 2 +- tests/expectations/nested_nonzero.cpp | 2 +- tests/expectations/nested_nonzero.pyx | 2 +- tests/expectations/nested_nonzero.tag.c | 2 +- .../expectations/nested_nonzero.tag.compat.c | 2 +- tests/expectations/nested_nonzero.tag.pyx | 2 +- 33 files changed, 186 insertions(+), 83 deletions(-) diff --git a/src/bindgen/cdecl.rs b/src/bindgen/cdecl.rs index 8075f97e5..f86c912a1 100644 --- a/src/bindgen/cdecl.rs +++ b/src/bindgen/cdecl.rs @@ -99,7 +99,9 @@ impl CDecl { fn build_type(&mut self, t: &Type, is_const: bool, config: &Config) { match t { - Type::Path(ref generic) => { + Type::Path { + path: ref generic, .. + } => { if is_const { assert!( self.type_qualifers.is_empty(), diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index ec8607731..776573d52 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -116,7 +116,7 @@ impl EnumVariant { if inline_tag_field { res.push(Field::from_name_and_type( inline_name.map_or_else(|| "tag".to_string(), |name| format!("{}_tag", name)), - Type::Path(GenericPath::new(Path::new("Tag"), vec![])), + Type::for_path(GenericPath::new(Path::new("Tag"), vec![])), )); } @@ -507,7 +507,7 @@ impl Item for Enum { if let VariantBody::Body { ref mut body, .. } = variant.body { let path = Path::new(new_tag.clone()); let generic_path = GenericPath::new(path, vec![]); - body.fields[0].ty = Type::Path(generic_path); + body.fields[0].ty = Type::for_path(generic_path); } } } diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index dea5dd1fb..dc8ac0778 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -352,7 +352,7 @@ trait SynFnArgHelpers { } fn gen_self_type(receiver: &syn::Receiver) -> Type { - let self_ty = Type::Path(GenericPath::self_path()); + let self_ty = Type::for_path(GenericPath::self_path()); if receiver.reference.is_none() { return self_ty; } diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index 7bc0a6430..895cf68ed 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -341,7 +341,11 @@ pub enum Type { // to code generation or something. is_ref: bool, }, - Path(GenericPath), + Path { + path: GenericPath, + is_nullable: bool, + is_zeroable: bool, + }, Primitive(PrimitiveType), Array(Box, ArrayLength), FuncPtr { @@ -361,6 +365,16 @@ impl Type { } } + pub fn for_path(path: GenericPath) -> Self { + Type::Path { + path, + // Assume that the type this name refers to is both nullable and zeroable, until we + // find otherwise. + is_nullable: true, + is_zeroable: true, + } + } + pub fn load(ty: &syn::Type) -> Result, String> { let converted = match *ty { syn::Type::Reference(ref reference) => { @@ -409,7 +423,7 @@ impl Type { } Type::Primitive(prim) } else { - Type::Path(generic_path) + Type::for_path(generic_path) } } syn::Type::Array(syn::TypeArray { @@ -510,21 +524,45 @@ impl Type { } } + pub fn is_zeroable(&self) -> bool { + match *self { + Type::Primitive(PrimitiveType::Integer { zeroable, .. }) => zeroable, + Type::Path { is_zeroable, .. } => is_zeroable, + _ => true, + } + } + pub fn make_zeroable(&self) -> Option { - let (kind, signed) = match *self { + match *self { Type::Primitive(PrimitiveType::Integer { + kind, + signed, zeroable: false, + }) => Some(Type::Primitive(PrimitiveType::Integer { kind, signed, - }) => (kind, signed), - _ => return None, - }; + zeroable: true, + })), + Type::Path { + ref path, + is_nullable, + is_zeroable: false, + } => Some(Type::Path { + path: path.clone(), + is_nullable, + is_zeroable: true, + }), + _ => None, + } + } - Some(Type::Primitive(PrimitiveType::Integer { - kind, - signed, - zeroable: true, - })) + pub fn is_nullable(&self) -> bool { + match *self { + Type::Ptr { is_nullable, .. } => is_nullable, + Type::FuncPtr { is_nullable, .. } => is_nullable, + Type::Path { is_nullable, .. } => is_nullable, + _ => true, + } } pub fn make_nullable(&self) -> Option { @@ -549,13 +587,22 @@ impl Type { args: args.clone(), is_nullable: true, }), + Type::Path { + ref path, + is_nullable: false, + is_zeroable, + } => Some(Type::Path { + path: path.clone(), + is_nullable: true, + is_zeroable, + }), _ => None, } } fn nonzero_to_primitive(&self) -> Option { let path = match *self { - Type::Path(ref p) => p, + Type::Path { ref path, .. } => path, _ => return None, }; @@ -595,12 +642,38 @@ impl Type { transparent_types: &TransparentTypes, ) -> Option { let path = match *self { - Type::Path(ref p) => p, + Type::Path { ref path, .. } => path, _ => return None, }; if path.generics().is_empty() { - return self.nonzero_to_primitive(); + let primitive = self.nonzero_to_primitive(); + if primitive.is_some() { + return primitive; + } + } + + // Repeatedly follow any typedefs or transparent structs until we reach a "real" type, and + // look up whether it is nullable and/or zeroable, saving that information so that we can + // use it later. + if let Some(transparent) = transparent_types.is_transparent(self) { + // Make sure to do another round of simplifying each time we follow a typedef or + // transparent struct link. + let mut current = match transparent.simplified_type(config, transparent_types) { + Some(current) => current, + None => transparent, + }; + while let Some(transparent) = transparent_types.is_transparent(¤t) { + current = match transparent.simplified_type(config, transparent_types) { + Some(current) => current, + None => transparent, + }; + } + return Some(Type::Path { + path: path.clone(), + is_nullable: current.is_nullable(), + is_zeroable: current.is_zeroable(), + }); } if path.generics().len() != 1 { @@ -608,25 +681,12 @@ impl Type { } let unsimplified_generic = &path.generics()[0]; - let mut generic = match unsimplified_generic.simplified_type(config, transparent_types) { + let generic = match unsimplified_generic.simplified_type(config, transparent_types) { Some(generic) => Cow::Owned(generic), None => Cow::Borrowed(unsimplified_generic), }; match path.name() { "Option" => { - // Repeatedly follow any typedefs or transparent structs until we reach a type that - // has its own "real" type in C/C++. - while let Some(transparent) = transparent_types.is_transparent(&generic) { - // Make sure to do another round of simplifying each time we follow a typedef - // or transparent struct link. - generic = match transparent.simplified_type(config, transparent_types) { - Some(generic) => Cow::Owned(generic), - None => Cow::Owned(transparent), - }; - } - - // Once we've found the base type for the Option's generic, see if we can take - // advantage of any nullable/zeroable layout optimizations. if let Some(nullable) = generic.make_nullable() { return Some(nullable); } @@ -667,7 +727,11 @@ impl Type { } pub fn replace_self_with(&mut self, self_ty: &Path) { - if let Type::Path(ref mut generic_path) = *self { + if let Type::Path { + path: ref mut generic_path, + .. + } = *self + { generic_path.replace_self_with(self_ty); } self.visit_types(|ty| ty.replace_self_with(self_ty)) @@ -676,7 +740,7 @@ impl Type { fn visit_types(&mut self, mut visitor: impl FnMut(&mut Type)) { match *self { Type::Array(ref mut ty, ..) | Type::Ptr { ref mut ty, .. } => visitor(ty), - Type::Path(ref mut path) => { + Type::Path { ref mut path, .. } => { for generic in path.generics_mut() { visitor(generic); } @@ -700,7 +764,9 @@ impl Type { loop { match *current { Type::Ptr { ref ty, .. } => current = ty, - Type::Path(ref generic) => { + Type::Path { + path: ref generic, .. + } => { return Some(generic.path().clone()); } Type::Primitive(..) => { @@ -729,7 +795,10 @@ impl Type { is_nullable, is_ref, }, - Type::Path(ref generic_path) => { + Type::Path { + path: ref generic_path, + .. + } => { for &(param, value) in mappings { if generic_path.path() == param { return value.clone(); @@ -744,7 +813,7 @@ impl Type { .map(|x| x.specialize(mappings)) .collect(), ); - Type::Path(specialized) + Type::for_path(specialized) } Type::Primitive(ref primitive) => Type::Primitive(primitive.clone()), Type::Array(ref ty, ref constant) => { @@ -776,7 +845,9 @@ impl Type { Type::Ptr { ref ty, .. } => { ty.add_dependencies_ignoring_generics(generic_params, library, out); } - Type::Path(ref generic) => { + Type::Path { + path: ref generic, .. + } => { for generic_value in generic.generics() { generic_value.add_dependencies_ignoring_generics(generic_params, library, out); } @@ -826,7 +897,9 @@ impl Type { Type::Ptr { ref ty, .. } => { ty.add_monomorphs(library, out); } - Type::Path(ref generic) => { + Type::Path { + path: ref generic, .. + } => { if generic.generics().is_empty() || out.contains(&generic) { return; } @@ -858,7 +931,9 @@ impl Type { Type::Ptr { ref mut ty, .. } => { ty.rename_for_config(config, generic_params); } - Type::Path(ref mut ty) => { + Type::Path { + path: ref mut ty, .. + } => { ty.rename_for_config(config, generic_params); } Type::Primitive(_) => {} @@ -884,7 +959,10 @@ impl Type { Type::Ptr { ref mut ty, .. } => { ty.resolve_declaration_types(resolver); } - Type::Path(ref mut generic_path) => { + Type::Path { + path: ref mut generic_path, + .. + } => { generic_path.resolve_declaration_types(resolver); } Type::Primitive(_) => {} @@ -909,7 +987,10 @@ impl Type { Type::Ptr { ref mut ty, .. } => { ty.mangle_paths(monomorphs); } - Type::Path(ref mut generic_path) => { + Type::Path { + path: ref mut generic_path, + .. + } => { if generic_path.generics().is_empty() { return; } @@ -945,7 +1026,7 @@ impl Type { match *self { // FIXME: Shouldn't this look at ty.can_cmp_order() as well? Type::Ptr { is_ref, .. } => !is_ref, - Type::Path(..) => true, + Type::Path { .. } => true, Type::Primitive(ref p) => p.can_cmp_order(), Type::Array(..) => false, Type::FuncPtr { .. } => false, @@ -955,7 +1036,7 @@ impl Type { pub fn can_cmp_eq(&self) -> bool { match *self { Type::Ptr { ref ty, is_ref, .. } => !is_ref || ty.can_cmp_eq(), - Type::Path(..) => true, + Type::Path { .. } => true, Type::Primitive(ref p) => p.can_cmp_eq(), Type::Array(..) => false, Type::FuncPtr { .. } => true, diff --git a/src/bindgen/mangle.rs b/src/bindgen/mangle.rs index 909b4659c..d260916e1 100644 --- a/src/bindgen/mangle.rs +++ b/src/bindgen/mangle.rs @@ -66,7 +66,9 @@ impl<'a> Mangler<'a> { fn append_mangled_type(&mut self, ty: &Type, last: bool) { match *ty { - Type::Path(ref generic) => { + Type::Path { + path: ref generic, .. + } => { let sub_path = Mangler::new(generic.export_name(), generic.generics(), last, self.config) .mangle(); @@ -163,7 +165,7 @@ fn generics() { fn generic_path(path: &str, generics: &[Type]) -> Type { let path = Path::new(path); let generic_path = GenericPath::new(path, generics.to_owned()); - Type::Path(generic_path) + Type::for_path(generic_path) } // Foo => Foo_f32 diff --git a/src/bindgen/transparent_types.rs b/src/bindgen/transparent_types.rs index 3115a9559..9a027bf7a 100644 --- a/src/bindgen/transparent_types.rs +++ b/src/bindgen/transparent_types.rs @@ -36,7 +36,7 @@ impl TransparentTypes { pub fn is_transparent(&self, ty: &Type) -> Option { let generic_path = match ty { - Type::Path(p) => p, + Type::Path { path, .. } => path, _ => return None, }; let (resolved, generic_params) = self.transparent.get(generic_path.path())?; diff --git a/tests/expectations/exclude_generic_monomorph.both.c b/tests/expectations/exclude_generic_monomorph.both.c index b641f75f1..3cd22c934 100644 --- a/tests/expectations/exclude_generic_monomorph.both.c +++ b/tests/expectations/exclude_generic_monomorph.both.c @@ -21,8 +21,10 @@ ctypedef uint64_t Option_Foo #include #include +typedef uint64_t Foo; + typedef struct Bar { - uint64_t foo; + Foo foo; } Bar; void root(struct Bar f); diff --git a/tests/expectations/exclude_generic_monomorph.both.compat.c b/tests/expectations/exclude_generic_monomorph.both.compat.c index dc78696f3..ff29fd834 100644 --- a/tests/expectations/exclude_generic_monomorph.both.compat.c +++ b/tests/expectations/exclude_generic_monomorph.both.compat.c @@ -21,8 +21,10 @@ ctypedef uint64_t Option_Foo #include #include +typedef uint64_t Foo; + typedef struct Bar { - uint64_t foo; + Foo foo; } Bar; #ifdef __cplusplus diff --git a/tests/expectations/exclude_generic_monomorph.c b/tests/expectations/exclude_generic_monomorph.c index bcd03a7e8..0c1d6df95 100644 --- a/tests/expectations/exclude_generic_monomorph.c +++ b/tests/expectations/exclude_generic_monomorph.c @@ -21,8 +21,10 @@ ctypedef uint64_t Option_Foo #include #include +typedef uint64_t Foo; + typedef struct { - uint64_t foo; + Foo foo; } Bar; void root(Bar f); diff --git a/tests/expectations/exclude_generic_monomorph.compat.c b/tests/expectations/exclude_generic_monomorph.compat.c index a769cd0db..3db201cbd 100644 --- a/tests/expectations/exclude_generic_monomorph.compat.c +++ b/tests/expectations/exclude_generic_monomorph.compat.c @@ -21,8 +21,10 @@ ctypedef uint64_t Option_Foo #include #include +typedef uint64_t Foo; + typedef struct { - uint64_t foo; + Foo foo; } Bar; #ifdef __cplusplus diff --git a/tests/expectations/exclude_generic_monomorph.cpp b/tests/expectations/exclude_generic_monomorph.cpp index b641f75f1..3cd22c934 100644 --- a/tests/expectations/exclude_generic_monomorph.cpp +++ b/tests/expectations/exclude_generic_monomorph.cpp @@ -21,8 +21,10 @@ ctypedef uint64_t Option_Foo #include #include +typedef uint64_t Foo; + typedef struct Bar { - uint64_t foo; + Foo foo; } Bar; void root(struct Bar f); diff --git a/tests/expectations/exclude_generic_monomorph.pyx b/tests/expectations/exclude_generic_monomorph.pyx index b645aa72f..685ff9b56 100644 --- a/tests/expectations/exclude_generic_monomorph.pyx +++ b/tests/expectations/exclude_generic_monomorph.pyx @@ -24,7 +24,9 @@ cdef extern from *: cdef extern from *: + ctypedef uint64_t Foo; + ctypedef struct Bar: - uint64_t foo; + Foo foo; void root(Bar f); diff --git a/tests/expectations/exclude_generic_monomorph.tag.c b/tests/expectations/exclude_generic_monomorph.tag.c index a50286339..cc50effd0 100644 --- a/tests/expectations/exclude_generic_monomorph.tag.c +++ b/tests/expectations/exclude_generic_monomorph.tag.c @@ -21,8 +21,10 @@ ctypedef uint64_t Option_Foo #include #include +typedef uint64_t Foo; + struct Bar { - uint64_t foo; + Foo foo; }; void root(struct Bar f); diff --git a/tests/expectations/exclude_generic_monomorph.tag.compat.c b/tests/expectations/exclude_generic_monomorph.tag.compat.c index 9092d856b..3bd4d5037 100644 --- a/tests/expectations/exclude_generic_monomorph.tag.compat.c +++ b/tests/expectations/exclude_generic_monomorph.tag.compat.c @@ -21,8 +21,10 @@ ctypedef uint64_t Option_Foo #include #include +typedef uint64_t Foo; + struct Bar { - uint64_t foo; + Foo foo; }; #ifdef __cplusplus diff --git a/tests/expectations/exclude_generic_monomorph.tag.pyx b/tests/expectations/exclude_generic_monomorph.tag.pyx index c8cdf1fa3..514f5fa88 100644 --- a/tests/expectations/exclude_generic_monomorph.tag.pyx +++ b/tests/expectations/exclude_generic_monomorph.tag.pyx @@ -24,7 +24,9 @@ cdef extern from *: cdef extern from *: + ctypedef uint64_t Foo; + cdef struct Bar: - uint64_t foo; + Foo foo; void root(Bar f); diff --git a/tests/expectations/nested_nonnull.both.c b/tests/expectations/nested_nonnull.both.c index 2bd11c741..8266b1a88 100644 --- a/tests/expectations/nested_nonnull.both.c +++ b/tests/expectations/nested_nonnull.both.c @@ -7,14 +7,14 @@ typedef int32_t (*DoFn)(int32_t x, int32_t y); typedef struct StructWithOptionalFunctionPointer { DoFn func; - int32_t (*maybe_func)(int32_t x, int32_t y); + DoFn maybe_func; } StructWithOptionalFunctionPointer; typedef uint32_t *NonNullAlias_u32; typedef struct StructWithOptionalNonNullPointer { NonNullAlias_u32 data; - uint32_t *maybe_data; + NonNullAlias_u32 maybe_data; } StructWithOptionalNonNullPointer; void root(struct StructWithOptionalFunctionPointer swofp, diff --git a/tests/expectations/nested_nonnull.both.compat.c b/tests/expectations/nested_nonnull.both.compat.c index e268acfa5..fe7e48ef3 100644 --- a/tests/expectations/nested_nonnull.both.compat.c +++ b/tests/expectations/nested_nonnull.both.compat.c @@ -7,14 +7,14 @@ typedef int32_t (*DoFn)(int32_t x, int32_t y); typedef struct StructWithOptionalFunctionPointer { DoFn func; - int32_t (*maybe_func)(int32_t x, int32_t y); + DoFn maybe_func; } StructWithOptionalFunctionPointer; typedef uint32_t *NonNullAlias_u32; typedef struct StructWithOptionalNonNullPointer { NonNullAlias_u32 data; - uint32_t *maybe_data; + NonNullAlias_u32 maybe_data; } StructWithOptionalNonNullPointer; #ifdef __cplusplus diff --git a/tests/expectations/nested_nonnull.c b/tests/expectations/nested_nonnull.c index bbc953016..a18005013 100644 --- a/tests/expectations/nested_nonnull.c +++ b/tests/expectations/nested_nonnull.c @@ -7,14 +7,14 @@ typedef int32_t (*DoFn)(int32_t x, int32_t y); typedef struct { DoFn func; - int32_t (*maybe_func)(int32_t x, int32_t y); + DoFn maybe_func; } StructWithOptionalFunctionPointer; typedef uint32_t *NonNullAlias_u32; typedef struct { NonNullAlias_u32 data; - uint32_t *maybe_data; + NonNullAlias_u32 maybe_data; } StructWithOptionalNonNullPointer; void root(StructWithOptionalFunctionPointer swofp, StructWithOptionalNonNullPointer swonnp); diff --git a/tests/expectations/nested_nonnull.compat.c b/tests/expectations/nested_nonnull.compat.c index 1a73626ea..b679f087a 100644 --- a/tests/expectations/nested_nonnull.compat.c +++ b/tests/expectations/nested_nonnull.compat.c @@ -7,14 +7,14 @@ typedef int32_t (*DoFn)(int32_t x, int32_t y); typedef struct { DoFn func; - int32_t (*maybe_func)(int32_t x, int32_t y); + DoFn maybe_func; } StructWithOptionalFunctionPointer; typedef uint32_t *NonNullAlias_u32; typedef struct { NonNullAlias_u32 data; - uint32_t *maybe_data; + NonNullAlias_u32 maybe_data; } StructWithOptionalNonNullPointer; #ifdef __cplusplus diff --git a/tests/expectations/nested_nonnull.cpp b/tests/expectations/nested_nonnull.cpp index 0eb1c2344..a969d0de0 100644 --- a/tests/expectations/nested_nonnull.cpp +++ b/tests/expectations/nested_nonnull.cpp @@ -8,7 +8,7 @@ using DoFn = int32_t(*)(int32_t x, int32_t y); struct StructWithOptionalFunctionPointer { DoFn func; - int32_t (*maybe_func)(int32_t x, int32_t y); + DoFn maybe_func; }; template @@ -16,7 +16,7 @@ using NonNullAlias = T*; struct StructWithOptionalNonNullPointer { NonNullAlias data; - uint32_t *maybe_data; + NonNullAlias maybe_data; }; extern "C" { diff --git a/tests/expectations/nested_nonnull.pyx b/tests/expectations/nested_nonnull.pyx index 173504f07..df06a788a 100644 --- a/tests/expectations/nested_nonnull.pyx +++ b/tests/expectations/nested_nonnull.pyx @@ -10,12 +10,12 @@ cdef extern from *: ctypedef struct StructWithOptionalFunctionPointer: DoFn func; - int32_t (*maybe_func)(int32_t x, int32_t y); + DoFn maybe_func; ctypedef uint32_t *NonNullAlias_u32; ctypedef struct StructWithOptionalNonNullPointer: NonNullAlias_u32 data; - uint32_t *maybe_data; + NonNullAlias_u32 maybe_data; void root(StructWithOptionalFunctionPointer swofp, StructWithOptionalNonNullPointer swonnp); diff --git a/tests/expectations/nested_nonnull.tag.c b/tests/expectations/nested_nonnull.tag.c index d69c2ebf6..31822455e 100644 --- a/tests/expectations/nested_nonnull.tag.c +++ b/tests/expectations/nested_nonnull.tag.c @@ -7,14 +7,14 @@ typedef int32_t (*DoFn)(int32_t x, int32_t y); struct StructWithOptionalFunctionPointer { DoFn func; - int32_t (*maybe_func)(int32_t x, int32_t y); + DoFn maybe_func; }; typedef uint32_t *NonNullAlias_u32; struct StructWithOptionalNonNullPointer { NonNullAlias_u32 data; - uint32_t *maybe_data; + NonNullAlias_u32 maybe_data; }; void root(struct StructWithOptionalFunctionPointer swofp, diff --git a/tests/expectations/nested_nonnull.tag.compat.c b/tests/expectations/nested_nonnull.tag.compat.c index 44809c18a..766e6b85d 100644 --- a/tests/expectations/nested_nonnull.tag.compat.c +++ b/tests/expectations/nested_nonnull.tag.compat.c @@ -7,14 +7,14 @@ typedef int32_t (*DoFn)(int32_t x, int32_t y); struct StructWithOptionalFunctionPointer { DoFn func; - int32_t (*maybe_func)(int32_t x, int32_t y); + DoFn maybe_func; }; typedef uint32_t *NonNullAlias_u32; struct StructWithOptionalNonNullPointer { NonNullAlias_u32 data; - uint32_t *maybe_data; + NonNullAlias_u32 maybe_data; }; #ifdef __cplusplus diff --git a/tests/expectations/nested_nonnull.tag.pyx b/tests/expectations/nested_nonnull.tag.pyx index 0c6ec1093..c8fd406a5 100644 --- a/tests/expectations/nested_nonnull.tag.pyx +++ b/tests/expectations/nested_nonnull.tag.pyx @@ -10,12 +10,12 @@ cdef extern from *: cdef struct StructWithOptionalFunctionPointer: DoFn func; - int32_t (*maybe_func)(int32_t x, int32_t y); + DoFn maybe_func; ctypedef uint32_t *NonNullAlias_u32; cdef struct StructWithOptionalNonNullPointer: NonNullAlias_u32 data; - uint32_t *maybe_data; + NonNullAlias_u32 maybe_data; void root(StructWithOptionalFunctionPointer swofp, StructWithOptionalNonNullPointer swonnp); diff --git a/tests/expectations/nested_nonzero.both.c b/tests/expectations/nested_nonzero.both.c index 13e10d4f5..3d4681839 100644 --- a/tests/expectations/nested_nonzero.both.c +++ b/tests/expectations/nested_nonzero.both.c @@ -7,7 +7,7 @@ typedef uint32_t Handle_File; typedef struct Node { Handle_File file; - uint32_t maybe_file; + Handle_File maybe_file; } Node; void root(const struct Node *node); diff --git a/tests/expectations/nested_nonzero.both.compat.c b/tests/expectations/nested_nonzero.both.compat.c index 96969d771..ce6910853 100644 --- a/tests/expectations/nested_nonzero.both.compat.c +++ b/tests/expectations/nested_nonzero.both.compat.c @@ -7,7 +7,7 @@ typedef uint32_t Handle_File; typedef struct Node { Handle_File file; - uint32_t maybe_file; + Handle_File maybe_file; } Node; #ifdef __cplusplus diff --git a/tests/expectations/nested_nonzero.c b/tests/expectations/nested_nonzero.c index b7a2ccb77..baddb521b 100644 --- a/tests/expectations/nested_nonzero.c +++ b/tests/expectations/nested_nonzero.c @@ -7,7 +7,7 @@ typedef uint32_t Handle_File; typedef struct { Handle_File file; - uint32_t maybe_file; + Handle_File maybe_file; } Node; void root(const Node *node); diff --git a/tests/expectations/nested_nonzero.compat.c b/tests/expectations/nested_nonzero.compat.c index 628890b68..b5a88240d 100644 --- a/tests/expectations/nested_nonzero.compat.c +++ b/tests/expectations/nested_nonzero.compat.c @@ -7,7 +7,7 @@ typedef uint32_t Handle_File; typedef struct { Handle_File file; - uint32_t maybe_file; + Handle_File maybe_file; } Node; #ifdef __cplusplus diff --git a/tests/expectations/nested_nonzero.cpp b/tests/expectations/nested_nonzero.cpp index 270b6507c..4197f261a 100644 --- a/tests/expectations/nested_nonzero.cpp +++ b/tests/expectations/nested_nonzero.cpp @@ -11,7 +11,7 @@ using Handle = uint32_t; struct Node { Handle file; - uint32_t maybe_file; + Handle maybe_file; }; extern "C" { diff --git a/tests/expectations/nested_nonzero.pyx b/tests/expectations/nested_nonzero.pyx index caba1f3c0..318cdb4d4 100644 --- a/tests/expectations/nested_nonzero.pyx +++ b/tests/expectations/nested_nonzero.pyx @@ -10,6 +10,6 @@ cdef extern from *: ctypedef struct Node: Handle_File file; - uint32_t maybe_file; + Handle_File maybe_file; void root(const Node *node); diff --git a/tests/expectations/nested_nonzero.tag.c b/tests/expectations/nested_nonzero.tag.c index 9226df9c8..d079c2765 100644 --- a/tests/expectations/nested_nonzero.tag.c +++ b/tests/expectations/nested_nonzero.tag.c @@ -7,7 +7,7 @@ typedef uint32_t Handle_File; struct Node { Handle_File file; - uint32_t maybe_file; + Handle_File maybe_file; }; void root(const struct Node *node); diff --git a/tests/expectations/nested_nonzero.tag.compat.c b/tests/expectations/nested_nonzero.tag.compat.c index dfac1534b..5de240ea6 100644 --- a/tests/expectations/nested_nonzero.tag.compat.c +++ b/tests/expectations/nested_nonzero.tag.compat.c @@ -7,7 +7,7 @@ typedef uint32_t Handle_File; struct Node { Handle_File file; - uint32_t maybe_file; + Handle_File maybe_file; }; #ifdef __cplusplus diff --git a/tests/expectations/nested_nonzero.tag.pyx b/tests/expectations/nested_nonzero.tag.pyx index 9e80816d6..752d93cef 100644 --- a/tests/expectations/nested_nonzero.tag.pyx +++ b/tests/expectations/nested_nonzero.tag.pyx @@ -10,6 +10,6 @@ cdef extern from *: cdef struct Node: Handle_File file; - uint32_t maybe_file; + Handle_File maybe_file; void root(const Node *node);