From 41b7866c148fd7bbef17c3a9d2ba22768f486ec6 Mon Sep 17 00:00:00 2001 From: Nick Wilcox Date: Sun, 2 Aug 2020 17:34:29 +1000 Subject: [PATCH] Add support for an optional attribute on pointers whose nullability can be inferred from the Rust type. --- docs.md | 4 ++ src/bindgen/cdecl.rs | 30 ++++++--- src/bindgen/config.rs | 3 + src/bindgen/ir/ty.rs | 65 +++++++++++++++++-- src/bindgen/mangle.rs | 4 +- tests/expectations/both/nonnull_attribute.c | 52 +++++++++++++++ .../both/nonnull_attribute.compat.c | 60 +++++++++++++++++ tests/expectations/nonnull_attribute.c | 52 +++++++++++++++ tests/expectations/nonnull_attribute.compat.c | 60 +++++++++++++++++ tests/expectations/nonnull_attribute.cpp | 57 ++++++++++++++++ tests/expectations/tag/nonnull_attribute.c | 52 +++++++++++++++ .../tag/nonnull_attribute.compat.c | 60 +++++++++++++++++ tests/rust/nonnull_attribute.rs | 55 ++++++++++++++++ tests/rust/nonnull_attribute.toml | 9 +++ 14 files changed, 549 insertions(+), 14 deletions(-) create mode 100644 tests/expectations/both/nonnull_attribute.c create mode 100644 tests/expectations/both/nonnull_attribute.compat.c create mode 100644 tests/expectations/nonnull_attribute.c create mode 100644 tests/expectations/nonnull_attribute.compat.c create mode 100644 tests/expectations/nonnull_attribute.cpp create mode 100644 tests/expectations/tag/nonnull_attribute.c create mode 100644 tests/expectations/tag/nonnull_attribute.compat.c create mode 100644 tests/rust/nonnull_attribute.rs create mode 100644 tests/rust/nonnull_attribute.toml diff --git a/docs.md b/docs.md index 3b2b7f6..a659791 100644 --- a/docs.md +++ b/docs.md @@ -476,6 +476,10 @@ tab_width = 3 # default: "auto" documentation_style = "doxy" +# An optional string that, if present, will decorate all pointers that are +# required to be non null. Nullability is inferred from the Rust type: `&T`, +# `&mut T` and `NonNull` are all require a valid pointer value. +non_null_attribute = "_Nonnull" diff --git a/src/bindgen/cdecl.rs b/src/bindgen/cdecl.rs index 9892df8..9f90e8c 100644 --- a/src/bindgen/cdecl.rs +++ b/src/bindgen/cdecl.rs @@ -14,7 +14,7 @@ use crate::bindgen::{Config, Language}; // http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf enum CDeclarator { - Ptr(bool), + Ptr(bool, bool), Ref, Array(String), Func(Vec<(Option, CDecl)>, bool), @@ -115,13 +115,21 @@ impl CDecl { } Type::ConstPtr(ref t) => { - self.declarators.push(CDeclarator::Ptr(is_const)); + self.declarators.push(CDeclarator::Ptr(is_const, false)); self.build_type(t, true); } Type::Ptr(ref t) => { - self.declarators.push(CDeclarator::Ptr(is_const)); + self.declarators.push(CDeclarator::Ptr(is_const, false)); self.build_type(t, false); } + Type::NonNullPtr(ref t) => { + self.declarators.push(CDeclarator::Ptr(is_const, true)); + self.build_type(t, false); + } + Type::ConstNonNullPtr(ref t) => { + self.declarators.push(CDeclarator::Ptr(is_const, true)); + self.build_type(t, true); + } Type::Ref(ref t) => { self.declarators.push(CDeclarator::Ref); self.build_type(t, true); @@ -140,7 +148,7 @@ impl CDecl { .iter() .map(|(ref name, ref ty)| (name.clone(), CDecl::from_type(ty))) .collect(); - self.declarators.push(CDeclarator::Ptr(false)); + self.declarators.push(CDeclarator::Ptr(false, false)); self.declarators.push(CDeclarator::Func(args, false)); self.build_type(ret, false); } @@ -178,11 +186,17 @@ impl CDecl { let next_is_pointer = iter_rev.peek().map_or(false, |x| x.is_ptr()); match *declarator { - CDeclarator::Ptr(ref is_const) => { - if *is_const { - out.write("*const "); + CDeclarator::Ptr(ref is_const, ref is_nonnull) => { + let non_null_attribute = if *is_nonnull { + config.non_null_attribute.as_ref() } else { - out.write("*"); + None + }; + match (non_null_attribute, is_const) { + (None, true) => out.write("*const "), + (None, false) => out.write("*"), + (Some(attr), true) => write!(out, "*const {} ", attr), + (Some(attr), false) => write!(out, "* {} ", attr), } } CDeclarator::Ref => { diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index eed84c5..05a1eb3 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -765,6 +765,8 @@ pub struct Config { pub documentation: bool, /// How documentation comments should be styled. pub documentation_style: DocumentationStyle, + /// Optional attribute to apply to pointers that are required to not be null + pub non_null_attribute: Option, } impl Default for Config { @@ -800,6 +802,7 @@ impl Default for Config { defines: HashMap::new(), documentation: true, documentation_style: DocumentationStyle::Auto, + non_null_attribute: None, } } } diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index 9d5ed53..9e94815 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -211,6 +211,8 @@ impl ArrayLength { pub enum Type { ConstPtr(Box), Ptr(Box), + ConstNonNullPtr(Box), + NonNullPtr(Box), Ref(Box), MutRef(Box), Path(GenericPath), @@ -235,8 +237,8 @@ impl Type { }; match reference.mutability { - Some(_) => Type::Ptr(Box::new(converted)), - None => Type::ConstPtr(Box::new(converted)), + Some(_) => Type::NonNullPtr(Box::new(converted)), + None => Type::ConstNonNullPtr(Box::new(converted)), } } syn::Type::Ptr(ref pointer) => { @@ -369,12 +371,25 @@ impl Type { pub fn is_repr_ptr(&self) -> bool { match *self { Type::Ptr(..) => true, + Type::NonNullPtr(..) => true, Type::ConstPtr(..) => true, + Type::ConstNonNullPtr(..) => true, Type::FuncPtr(..) => true, _ => false, } } + pub fn make_nullable(&self) -> Option { + match self.clone() { + Type::Ptr(x) => Some(Type::Ptr(x)), + Type::NonNullPtr(x) => Some(Type::Ptr(x)), + Type::ConstPtr(x) => Some(Type::ConstPtr(x)), + Type::ConstNonNullPtr(x) => Some(Type::ConstPtr(x)), + Type::FuncPtr(x, y) => Some(Type::FuncPtr(x, y)), + _ => None, + } + } + fn simplified_type(&self) -> Option { let path = match *self { Type::Path(ref p) => p, @@ -390,8 +405,8 @@ impl Type { match path.name() { // FIXME(#223): This is not quite correct. - "Option" if generic.is_repr_ptr() => Some(generic), - "NonNull" => Some(Type::Ptr(Box::new(generic))), + "Option" if generic.is_repr_ptr() => generic.make_nullable(), + "NonNull" => Some(Type::NonNullPtr(Box::new(generic))), "Cell" => Some(generic), _ => None, } @@ -409,6 +424,8 @@ impl Type { | Type::MutRef(ref mut ty) | Type::Ref(ref mut ty) | Type::Ptr(ref mut ty) + | Type::NonNullPtr(ref mut ty) + | Type::ConstNonNullPtr(ref mut ty) | Type::ConstPtr(ref mut ty) => ty.replace_self_with(self_ty), Type::Path(ref mut generic_path) => { generic_path.replace_self_with(self_ty); @@ -429,6 +446,8 @@ impl Type { match *current { Type::ConstPtr(ref ty) => current = ty, Type::Ptr(ref ty) => current = ty, + Type::NonNullPtr(ref ty) => current = ty, + Type::ConstNonNullPtr(ref ty) => current = ty, Type::Ref(ref ty) => current = ty, Type::MutRef(ref ty) => current = ty, Type::Path(ref generic) => { @@ -451,6 +470,10 @@ impl Type { match *self { Type::ConstPtr(ref ty) => Type::ConstPtr(Box::new(ty.specialize(mappings))), Type::Ptr(ref ty) => Type::Ptr(Box::new(ty.specialize(mappings))), + Type::NonNullPtr(ref ty) => Type::NonNullPtr(Box::new(ty.specialize(mappings))), + Type::ConstNonNullPtr(ref ty) => { + Type::ConstNonNullPtr(Box::new(ty.specialize(mappings))) + } Type::Ref(ref ty) => Type::Ref(Box::new(ty.specialize(mappings))), Type::MutRef(ref ty) => Type::MutRef(Box::new(ty.specialize(mappings))), Type::Path(ref generic_path) => { @@ -497,6 +520,12 @@ impl Type { Type::Ptr(ref ty) => { ty.add_dependencies_ignoring_generics(generic_params, library, out); } + Type::NonNullPtr(ref ty) => { + ty.add_dependencies_ignoring_generics(generic_params, library, out); + } + Type::ConstNonNullPtr(ref ty) => { + ty.add_dependencies_ignoring_generics(generic_params, library, out); + } Type::Ref(ref ty) | Type::MutRef(ref ty) => { ty.add_dependencies_ignoring_generics(generic_params, library, out); } @@ -551,6 +580,12 @@ impl Type { Type::Ptr(ref ty) => { ty.add_monomorphs(library, out); } + Type::NonNullPtr(ref ty) => { + ty.add_monomorphs(library, out); + } + Type::ConstNonNullPtr(ref ty) => { + ty.add_monomorphs(library, out); + } Type::Ref(ref ty) | Type::MutRef(ref ty) => { ty.add_monomorphs(library, out); } @@ -587,6 +622,12 @@ impl Type { Type::Ptr(ref mut ty) => { ty.rename_for_config(config, generic_params); } + Type::NonNullPtr(ref mut ty) => { + ty.rename_for_config(config, generic_params); + } + Type::ConstNonNullPtr(ref mut ty) => { + ty.rename_for_config(config, generic_params); + } Type::Ref(ref mut ty) | Type::MutRef(ref mut ty) => { ty.rename_for_config(config, generic_params); } @@ -615,6 +656,12 @@ impl Type { Type::Ptr(ref mut ty) => { ty.resolve_declaration_types(resolver); } + Type::NonNullPtr(ref mut ty) => { + ty.resolve_declaration_types(resolver); + } + Type::ConstNonNullPtr(ref mut ty) => { + ty.resolve_declaration_types(resolver); + } Type::Ref(ref mut ty) | Type::MutRef(ref mut ty) => { ty.resolve_declaration_types(resolver); } @@ -642,6 +689,12 @@ impl Type { Type::Ptr(ref mut ty) => { ty.mangle_paths(monomorphs); } + Type::NonNullPtr(ref mut ty) => { + ty.mangle_paths(monomorphs); + } + Type::ConstNonNullPtr(ref mut ty) => { + ty.mangle_paths(monomorphs); + } Type::Ref(ref mut ty) | Type::MutRef(ref mut ty) => { ty.mangle_paths(monomorphs); } @@ -677,6 +730,8 @@ impl Type { match *self { Type::ConstPtr(..) => true, Type::Ptr(..) => true, + Type::NonNullPtr(..) => true, + Type::ConstNonNullPtr(..) => true, Type::Ref(..) | Type::MutRef(..) => false, Type::Path(..) => true, Type::Primitive(ref p) => p.can_cmp_order(), @@ -689,6 +744,8 @@ impl Type { match *self { Type::ConstPtr(..) => true, Type::Ptr(..) => true, + Type::NonNullPtr(..) => true, + Type::ConstNonNullPtr(..) => true, Type::Ref(..) | Type::MutRef(..) => false, Type::Path(..) => true, Type::Primitive(ref p) => p.can_cmp_eq(), diff --git a/src/bindgen/mangle.rs b/src/bindgen/mangle.rs index 27a37f8..e20b03b 100644 --- a/src/bindgen/mangle.rs +++ b/src/bindgen/mangle.rs @@ -58,11 +58,11 @@ impl<'a> Mangler<'a> { Type::Primitive(ref primitive) => { self.output.push_str(primitive.to_repr_rust()); } - Type::Ptr(ref ty) | Type::MutRef(ref ty) => { + Type::Ptr(ref ty) | Type::MutRef(ref ty) | Type::NonNullPtr(ref ty) => { self.push(Separator::BeginMutPtr); self.append_mangled_type(&**ty, last); } - Type::ConstPtr(ref ty) | Type::Ref(ref ty) => { + Type::ConstPtr(ref ty) | Type::Ref(ref ty) | Type::ConstNonNullPtr(ref ty) => { self.push(Separator::BeginConstPtr); self.append_mangled_type(&**ty, last); } diff --git a/tests/expectations/both/nonnull_attribute.c b/tests/expectations/both/nonnull_attribute.c new file mode 100644 index 0000000..6c4c1e2 --- /dev/null +++ b/tests/expectations/both/nonnull_attribute.c @@ -0,0 +1,52 @@ +#ifdef __clang__ +#define CBINDGEN_NONNULL _Nonnull +#else +#define CBINDGEN_NONNULL +#endif + + +#include +#include +#include +#include + +typedef struct Opaque Opaque; + +typedef struct Pointers_u64 { + float * CBINDGEN_NONNULL a; + uint64_t * CBINDGEN_NONNULL b; + Opaque * CBINDGEN_NONNULL c; + uint64_t * CBINDGEN_NONNULL * CBINDGEN_NONNULL d; + float * CBINDGEN_NONNULL * CBINDGEN_NONNULL e; + Opaque * CBINDGEN_NONNULL * CBINDGEN_NONNULL f; + uint64_t *g; + int32_t *h; + int32_t * CBINDGEN_NONNULL *i; + const uint64_t *j; + uint64_t *k; +} Pointers_u64; + +typedef struct References { + const Opaque * CBINDGEN_NONNULL a; + Opaque * CBINDGEN_NONNULL b; + const Opaque *c; + Opaque *d; +} References; + +void mut_ref_arg(const Pointers_u64 * CBINDGEN_NONNULL arg); + +void mutltiple_args(int32_t * CBINDGEN_NONNULL arg, + Pointers_u64 *foo, + Opaque * CBINDGEN_NONNULL * CBINDGEN_NONNULL d); + +void nullable_const_ptr(const Pointers_u64 *arg); + +void nullable_mut_ptr(Pointers_u64 *arg); + +void optional_mut_ref_arg(const Pointers_u64 *arg); + +void optional_ref_arg(Pointers_u64 *arg); + +void ref_arg(Pointers_u64 * CBINDGEN_NONNULL arg); + +void value_arg(References arg); diff --git a/tests/expectations/both/nonnull_attribute.compat.c b/tests/expectations/both/nonnull_attribute.compat.c new file mode 100644 index 0000000..dc572d2 --- /dev/null +++ b/tests/expectations/both/nonnull_attribute.compat.c @@ -0,0 +1,60 @@ +#ifdef __clang__ +#define CBINDGEN_NONNULL _Nonnull +#else +#define CBINDGEN_NONNULL +#endif + + +#include +#include +#include +#include + +typedef struct Opaque Opaque; + +typedef struct Pointers_u64 { + float * CBINDGEN_NONNULL a; + uint64_t * CBINDGEN_NONNULL b; + Opaque * CBINDGEN_NONNULL c; + uint64_t * CBINDGEN_NONNULL * CBINDGEN_NONNULL d; + float * CBINDGEN_NONNULL * CBINDGEN_NONNULL e; + Opaque * CBINDGEN_NONNULL * CBINDGEN_NONNULL f; + uint64_t *g; + int32_t *h; + int32_t * CBINDGEN_NONNULL *i; + const uint64_t *j; + uint64_t *k; +} Pointers_u64; + +typedef struct References { + const Opaque * CBINDGEN_NONNULL a; + Opaque * CBINDGEN_NONNULL b; + const Opaque *c; + Opaque *d; +} References; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void mut_ref_arg(const Pointers_u64 * CBINDGEN_NONNULL arg); + +void mutltiple_args(int32_t * CBINDGEN_NONNULL arg, + Pointers_u64 *foo, + Opaque * CBINDGEN_NONNULL * CBINDGEN_NONNULL d); + +void nullable_const_ptr(const Pointers_u64 *arg); + +void nullable_mut_ptr(Pointers_u64 *arg); + +void optional_mut_ref_arg(const Pointers_u64 *arg); + +void optional_ref_arg(Pointers_u64 *arg); + +void ref_arg(Pointers_u64 * CBINDGEN_NONNULL arg); + +void value_arg(References arg); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/nonnull_attribute.c b/tests/expectations/nonnull_attribute.c new file mode 100644 index 0000000..e644970 --- /dev/null +++ b/tests/expectations/nonnull_attribute.c @@ -0,0 +1,52 @@ +#ifdef __clang__ +#define CBINDGEN_NONNULL _Nonnull +#else +#define CBINDGEN_NONNULL +#endif + + +#include +#include +#include +#include + +typedef struct Opaque Opaque; + +typedef struct { + float * CBINDGEN_NONNULL a; + uint64_t * CBINDGEN_NONNULL b; + Opaque * CBINDGEN_NONNULL c; + uint64_t * CBINDGEN_NONNULL * CBINDGEN_NONNULL d; + float * CBINDGEN_NONNULL * CBINDGEN_NONNULL e; + Opaque * CBINDGEN_NONNULL * CBINDGEN_NONNULL f; + uint64_t *g; + int32_t *h; + int32_t * CBINDGEN_NONNULL *i; + const uint64_t *j; + uint64_t *k; +} Pointers_u64; + +typedef struct { + const Opaque * CBINDGEN_NONNULL a; + Opaque * CBINDGEN_NONNULL b; + const Opaque *c; + Opaque *d; +} References; + +void mut_ref_arg(const Pointers_u64 * CBINDGEN_NONNULL arg); + +void mutltiple_args(int32_t * CBINDGEN_NONNULL arg, + Pointers_u64 *foo, + Opaque * CBINDGEN_NONNULL * CBINDGEN_NONNULL d); + +void nullable_const_ptr(const Pointers_u64 *arg); + +void nullable_mut_ptr(Pointers_u64 *arg); + +void optional_mut_ref_arg(const Pointers_u64 *arg); + +void optional_ref_arg(Pointers_u64 *arg); + +void ref_arg(Pointers_u64 * CBINDGEN_NONNULL arg); + +void value_arg(References arg); diff --git a/tests/expectations/nonnull_attribute.compat.c b/tests/expectations/nonnull_attribute.compat.c new file mode 100644 index 0000000..991c652 --- /dev/null +++ b/tests/expectations/nonnull_attribute.compat.c @@ -0,0 +1,60 @@ +#ifdef __clang__ +#define CBINDGEN_NONNULL _Nonnull +#else +#define CBINDGEN_NONNULL +#endif + + +#include +#include +#include +#include + +typedef struct Opaque Opaque; + +typedef struct { + float * CBINDGEN_NONNULL a; + uint64_t * CBINDGEN_NONNULL b; + Opaque * CBINDGEN_NONNULL c; + uint64_t * CBINDGEN_NONNULL * CBINDGEN_NONNULL d; + float * CBINDGEN_NONNULL * CBINDGEN_NONNULL e; + Opaque * CBINDGEN_NONNULL * CBINDGEN_NONNULL f; + uint64_t *g; + int32_t *h; + int32_t * CBINDGEN_NONNULL *i; + const uint64_t *j; + uint64_t *k; +} Pointers_u64; + +typedef struct { + const Opaque * CBINDGEN_NONNULL a; + Opaque * CBINDGEN_NONNULL b; + const Opaque *c; + Opaque *d; +} References; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void mut_ref_arg(const Pointers_u64 * CBINDGEN_NONNULL arg); + +void mutltiple_args(int32_t * CBINDGEN_NONNULL arg, + Pointers_u64 *foo, + Opaque * CBINDGEN_NONNULL * CBINDGEN_NONNULL d); + +void nullable_const_ptr(const Pointers_u64 *arg); + +void nullable_mut_ptr(Pointers_u64 *arg); + +void optional_mut_ref_arg(const Pointers_u64 *arg); + +void optional_ref_arg(Pointers_u64 *arg); + +void ref_arg(Pointers_u64 * CBINDGEN_NONNULL arg); + +void value_arg(References arg); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/nonnull_attribute.cpp b/tests/expectations/nonnull_attribute.cpp new file mode 100644 index 0000000..524d506 --- /dev/null +++ b/tests/expectations/nonnull_attribute.cpp @@ -0,0 +1,57 @@ +#ifdef __clang__ +#define CBINDGEN_NONNULL _Nonnull +#else +#define CBINDGEN_NONNULL +#endif + + +#include +#include +#include +#include + +struct Opaque; + +template +struct Pointers { + float * CBINDGEN_NONNULL a; + T * CBINDGEN_NONNULL b; + Opaque * CBINDGEN_NONNULL c; + T * CBINDGEN_NONNULL * CBINDGEN_NONNULL d; + float * CBINDGEN_NONNULL * CBINDGEN_NONNULL e; + Opaque * CBINDGEN_NONNULL * CBINDGEN_NONNULL f; + T *g; + int32_t *h; + int32_t * CBINDGEN_NONNULL *i; + const T *j; + T *k; +}; + +struct References { + const Opaque * CBINDGEN_NONNULL a; + Opaque * CBINDGEN_NONNULL b; + const Opaque *c; + Opaque *d; +}; + +extern "C" { + +void mut_ref_arg(const Pointers * CBINDGEN_NONNULL arg); + +void mutltiple_args(int32_t * CBINDGEN_NONNULL arg, + Pointers *foo, + Opaque * CBINDGEN_NONNULL * CBINDGEN_NONNULL d); + +void nullable_const_ptr(const Pointers *arg); + +void nullable_mut_ptr(Pointers *arg); + +void optional_mut_ref_arg(const Pointers *arg); + +void optional_ref_arg(Pointers *arg); + +void ref_arg(Pointers * CBINDGEN_NONNULL arg); + +void value_arg(References arg); + +} // extern "C" diff --git a/tests/expectations/tag/nonnull_attribute.c b/tests/expectations/tag/nonnull_attribute.c new file mode 100644 index 0000000..91f2c79 --- /dev/null +++ b/tests/expectations/tag/nonnull_attribute.c @@ -0,0 +1,52 @@ +#ifdef __clang__ +#define CBINDGEN_NONNULL _Nonnull +#else +#define CBINDGEN_NONNULL +#endif + + +#include +#include +#include +#include + +struct Opaque; + +struct Pointers_u64 { + float * CBINDGEN_NONNULL a; + uint64_t * CBINDGEN_NONNULL b; + struct Opaque * CBINDGEN_NONNULL c; + uint64_t * CBINDGEN_NONNULL * CBINDGEN_NONNULL d; + float * CBINDGEN_NONNULL * CBINDGEN_NONNULL e; + struct Opaque * CBINDGEN_NONNULL * CBINDGEN_NONNULL f; + uint64_t *g; + int32_t *h; + int32_t * CBINDGEN_NONNULL *i; + const uint64_t *j; + uint64_t *k; +}; + +struct References { + const struct Opaque * CBINDGEN_NONNULL a; + struct Opaque * CBINDGEN_NONNULL b; + const struct Opaque *c; + struct Opaque *d; +}; + +void mut_ref_arg(const struct Pointers_u64 * CBINDGEN_NONNULL arg); + +void mutltiple_args(int32_t * CBINDGEN_NONNULL arg, + struct Pointers_u64 *foo, + struct Opaque * CBINDGEN_NONNULL * CBINDGEN_NONNULL d); + +void nullable_const_ptr(const struct Pointers_u64 *arg); + +void nullable_mut_ptr(struct Pointers_u64 *arg); + +void optional_mut_ref_arg(const struct Pointers_u64 *arg); + +void optional_ref_arg(struct Pointers_u64 *arg); + +void ref_arg(struct Pointers_u64 * CBINDGEN_NONNULL arg); + +void value_arg(struct References arg); diff --git a/tests/expectations/tag/nonnull_attribute.compat.c b/tests/expectations/tag/nonnull_attribute.compat.c new file mode 100644 index 0000000..ef0a8fa --- /dev/null +++ b/tests/expectations/tag/nonnull_attribute.compat.c @@ -0,0 +1,60 @@ +#ifdef __clang__ +#define CBINDGEN_NONNULL _Nonnull +#else +#define CBINDGEN_NONNULL +#endif + + +#include +#include +#include +#include + +struct Opaque; + +struct Pointers_u64 { + float * CBINDGEN_NONNULL a; + uint64_t * CBINDGEN_NONNULL b; + struct Opaque * CBINDGEN_NONNULL c; + uint64_t * CBINDGEN_NONNULL * CBINDGEN_NONNULL d; + float * CBINDGEN_NONNULL * CBINDGEN_NONNULL e; + struct Opaque * CBINDGEN_NONNULL * CBINDGEN_NONNULL f; + uint64_t *g; + int32_t *h; + int32_t * CBINDGEN_NONNULL *i; + const uint64_t *j; + uint64_t *k; +}; + +struct References { + const struct Opaque * CBINDGEN_NONNULL a; + struct Opaque * CBINDGEN_NONNULL b; + const struct Opaque *c; + struct Opaque *d; +}; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void mut_ref_arg(const struct Pointers_u64 * CBINDGEN_NONNULL arg); + +void mutltiple_args(int32_t * CBINDGEN_NONNULL arg, + struct Pointers_u64 *foo, + struct Opaque * CBINDGEN_NONNULL * CBINDGEN_NONNULL d); + +void nullable_const_ptr(const struct Pointers_u64 *arg); + +void nullable_mut_ptr(struct Pointers_u64 *arg); + +void optional_mut_ref_arg(const struct Pointers_u64 *arg); + +void optional_ref_arg(struct Pointers_u64 *arg); + +void ref_arg(struct Pointers_u64 * CBINDGEN_NONNULL arg); + +void value_arg(struct References arg); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/rust/nonnull_attribute.rs b/tests/rust/nonnull_attribute.rs new file mode 100644 index 0000000..46e8f4d --- /dev/null +++ b/tests/rust/nonnull_attribute.rs @@ -0,0 +1,55 @@ +use std::ptr::NonNull; + +struct Opaque; + +#[repr(C)] +pub struct Pointers { + a: NonNull, + b: NonNull, + c: NonNull, + d: NonNull>, + e: NonNull>, + f: NonNull>, + g: Option>, + h: Option>, + i: Option>>, + j: *const T, + k: *mut T, +} + +#[repr(C)] +pub struct References<'a> { + a: &'a Opaque, + b: &'a mut Opaque, + c: Option<&'a Opaque>, + d: Option<&'a mut Opaque>, +} + +#[no_mangle] +pub extern "C" fn value_arg(arg: References<'static>) {} + +#[no_mangle] +pub extern "C" fn mutltiple_args( + arg: NonNull, + foo: *mut Pointers, + d: NonNull>, +) { +} + +#[no_mangle] +pub extern "C" fn mut_ref_arg(arg: &Pointers) {} + +#[no_mangle] +pub extern "C" fn ref_arg(arg: &mut Pointers) {} + +#[no_mangle] +pub extern "C" fn optional_mut_ref_arg(arg: Option<&Pointers>) {} + +#[no_mangle] +pub extern "C" fn optional_ref_arg(arg: Option<&mut Pointers>) {} + +#[no_mangle] +pub extern "C" fn nullable_const_ptr(arg: *const Pointers) {} + +#[no_mangle] +pub extern "C" fn nullable_mut_ptr(arg: *mut Pointers) {} diff --git a/tests/rust/nonnull_attribute.toml b/tests/rust/nonnull_attribute.toml new file mode 100644 index 0000000..ca2a341 --- /dev/null +++ b/tests/rust/nonnull_attribute.toml @@ -0,0 +1,9 @@ +header = """ +#ifdef __clang__ +#define CBINDGEN_NONNULL _Nonnull +#else +#define CBINDGEN_NONNULL +#endif +""" + +non_null_attribute = "CBINDGEN_NONNULL" \ No newline at end of file