diff --git a/src/bindgen/ir/documentation.rs b/src/bindgen/ir/documentation.rs index 1a6b318d2..53da91667 100644 --- a/src/bindgen/ir/documentation.rs +++ b/src/bindgen/ir/documentation.rs @@ -26,6 +26,12 @@ impl Documentation { Documentation { doc_comment: doc } } + pub fn simple(line: &str) -> Self { + Documentation { + doc_comment: vec![line.to_owned()], + } + } + pub fn none() -> Self { Documentation { doc_comment: Vec::new(), diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 46ab4c27a..71d0c0eb3 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -253,7 +253,11 @@ impl Enum { } } - pub fn load(item: &syn::ItemEnum, mod_cfg: Option<&Cfg>) -> Result { + pub fn load( + item: &syn::ItemEnum, + mod_cfg: Option<&Cfg>, + config: &Config, + ) -> Result { let repr = Repr::load(&item.attrs)?; if repr.style == ReprStyle::Rust && repr.ty.is_none() { return Err("Enum is not marked with a valid #[repr(prim)] or #[repr(C)].".to_owned()); @@ -289,6 +293,15 @@ impl Enum { } } + if config.enumeration.add_sentinel(&annotations) { + variants.push(EnumVariant::new( + "Sentinel".to_owned(), + None, + None, + Documentation::simple(" Must be last for serialization purposes"), + )); + } + let tag = if is_tagged { Some("Tag".to_string()) } else { @@ -596,11 +609,6 @@ impl Source for Enum { } variant.write(config, out); } - if config.enumeration.add_sentinel(&self.annotations) { - out.new_line(); - out.new_line(); - out.write("Sentinel /* this must be last for serialization purposes. */"); - } if config.language == Language::C && size.is_none() && config.style.generate_typedef() { out.close_brace(false); diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index 1a36722a4..f514fe74b 100644 --- a/src/bindgen/parser.rs +++ b/src/bindgen/parser.rs @@ -452,7 +452,7 @@ impl Parse { self.load_syn_union(config, crate_name, mod_cfg, item); } syn::Item::Enum(ref item) => { - self.load_syn_enum(crate_name, mod_cfg, item); + self.load_syn_enum(config, crate_name, mod_cfg, item); } syn::Item::Type(ref item) => { self.load_syn_ty(crate_name, mod_cfg, item); @@ -860,7 +860,13 @@ impl Parse { } /// Loads a `enum` declaration - fn load_syn_enum(&mut self, crate_name: &str, mod_cfg: Option<&Cfg>, item: &syn::ItemEnum) { + fn load_syn_enum( + &mut self, + config: &Config, + crate_name: &str, + mod_cfg: Option<&Cfg>, + item: &syn::ItemEnum, + ) { if item.generics.lifetimes().count() > 0 { info!( "Skip {}::{} - (has generics or lifetimes or where bounds).", @@ -869,7 +875,7 @@ impl Parse { return; } - match Enum::load(item, mod_cfg) { + match Enum::load(item, mod_cfg, config) { Ok(en) => { info!("Take {}::{}.", crate_name, &item.ident); self.enums.try_insert(en); diff --git a/tests/expectations/both/sentinel.c b/tests/expectations/both/sentinel.c new file mode 100644 index 000000000..f7a45c938 --- /dev/null +++ b/tests/expectations/both/sentinel.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include + +enum A { + A_A1, + A_A2, + A_A3, + /** + * Must be last for serialization purposes + */ + A_Sentinel, +}; +typedef uint8_t A; + +enum B { + B_B1, + B_B2, + B_B3, + /** + * Must be last for serialization purposes + */ + B_Sentinel, +}; +typedef uint8_t B; + +enum C_Tag { + C_C1, + C_C2, + C_C3, + /** + * Must be last for serialization purposes + */ + C_Sentinel, +}; +typedef uint8_t C_Tag; + +typedef struct C_C1_Body { + C_Tag tag; + uint32_t a; +} C_C1_Body; + +typedef struct C_C2_Body { + C_Tag tag; + uint32_t b; +} C_C2_Body; + +typedef union C { + C_Tag tag; + C_C1_Body c1; + C_C2_Body c2; +} C; + +void root(A a, B b, C c); diff --git a/tests/expectations/both/sentinel.compat.c b/tests/expectations/both/sentinel.compat.c new file mode 100644 index 000000000..95b1e0697 --- /dev/null +++ b/tests/expectations/both/sentinel.compat.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include + +enum A +#ifdef __cplusplus + : uint8_t +#endif // __cplusplus + { + A_A1, + A_A2, + A_A3, + /** + * Must be last for serialization purposes + */ + A_Sentinel, +}; +#ifndef __cplusplus +typedef uint8_t A; +#endif // __cplusplus + +enum B +#ifdef __cplusplus + : uint8_t +#endif // __cplusplus + { + B_B1, + B_B2, + B_B3, + /** + * Must be last for serialization purposes + */ + B_Sentinel, +}; +#ifndef __cplusplus +typedef uint8_t B; +#endif // __cplusplus + +enum C_Tag +#ifdef __cplusplus + : uint8_t +#endif // __cplusplus + { + C_C1, + C_C2, + C_C3, + /** + * Must be last for serialization purposes + */ + C_Sentinel, +}; +#ifndef __cplusplus +typedef uint8_t C_Tag; +#endif // __cplusplus + +typedef struct C_C1_Body { + C_Tag tag; + uint32_t a; +} C_C1_Body; + +typedef struct C_C2_Body { + C_Tag tag; + uint32_t b; +} C_C2_Body; + +typedef union C { + C_Tag tag; + C_C1_Body c1; + C_C2_Body c2; +} C; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root(A a, B b, C c); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/sentinel.c b/tests/expectations/sentinel.c new file mode 100644 index 000000000..27057f3aa --- /dev/null +++ b/tests/expectations/sentinel.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include + +enum A { + A_A1, + A_A2, + A_A3, + /** + * Must be last for serialization purposes + */ + A_Sentinel, +}; +typedef uint8_t A; + +enum B { + B_B1, + B_B2, + B_B3, + /** + * Must be last for serialization purposes + */ + B_Sentinel, +}; +typedef uint8_t B; + +enum C_Tag { + C_C1, + C_C2, + C_C3, + /** + * Must be last for serialization purposes + */ + C_Sentinel, +}; +typedef uint8_t C_Tag; + +typedef struct { + C_Tag tag; + uint32_t a; +} C_C1_Body; + +typedef struct { + C_Tag tag; + uint32_t b; +} C_C2_Body; + +typedef union { + C_Tag tag; + C_C1_Body c1; + C_C2_Body c2; +} C; + +void root(A a, B b, C c); diff --git a/tests/expectations/sentinel.compat.c b/tests/expectations/sentinel.compat.c new file mode 100644 index 000000000..e86d2d934 --- /dev/null +++ b/tests/expectations/sentinel.compat.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include + +enum A +#ifdef __cplusplus + : uint8_t +#endif // __cplusplus + { + A_A1, + A_A2, + A_A3, + /** + * Must be last for serialization purposes + */ + A_Sentinel, +}; +#ifndef __cplusplus +typedef uint8_t A; +#endif // __cplusplus + +enum B +#ifdef __cplusplus + : uint8_t +#endif // __cplusplus + { + B_B1, + B_B2, + B_B3, + /** + * Must be last for serialization purposes + */ + B_Sentinel, +}; +#ifndef __cplusplus +typedef uint8_t B; +#endif // __cplusplus + +enum C_Tag +#ifdef __cplusplus + : uint8_t +#endif // __cplusplus + { + C_C1, + C_C2, + C_C3, + /** + * Must be last for serialization purposes + */ + C_Sentinel, +}; +#ifndef __cplusplus +typedef uint8_t C_Tag; +#endif // __cplusplus + +typedef struct { + C_Tag tag; + uint32_t a; +} C_C1_Body; + +typedef struct { + C_Tag tag; + uint32_t b; +} C_C2_Body; + +typedef union { + C_Tag tag; + C_C1_Body c1; + C_C2_Body c2; +} C; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root(A a, B b, C c); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/sentinel.cpp b/tests/expectations/sentinel.cpp new file mode 100644 index 000000000..316d1ce0d --- /dev/null +++ b/tests/expectations/sentinel.cpp @@ -0,0 +1,52 @@ +#include +#include +#include +#include + +enum class A : uint8_t { + A_A1, + A_A2, + A_A3, + /// Must be last for serialization purposes + A_Sentinel, +}; + +enum class B : uint8_t { + B_B1, + B_B2, + B_B3, + /// Must be last for serialization purposes + B_Sentinel, +}; + +union C { + enum class Tag : uint8_t { + C_C1, + C_C2, + C_C3, + /// Must be last for serialization purposes + C_Sentinel, + }; + + struct C_C1_Body { + Tag tag; + uint32_t a; + }; + + struct C_C2_Body { + Tag tag; + uint32_t b; + }; + + struct { + Tag tag; + }; + C_C1_Body c1; + C_C2_Body c2; +}; + +extern "C" { + +void root(A a, B b, C c); + +} // extern "C" diff --git a/tests/expectations/tag/sentinel.c b/tests/expectations/tag/sentinel.c new file mode 100644 index 000000000..684eeb3eb --- /dev/null +++ b/tests/expectations/tag/sentinel.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include + +enum A { + A_A1, + A_A2, + A_A3, + /** + * Must be last for serialization purposes + */ + A_Sentinel, +}; +typedef uint8_t A; + +enum B { + B_B1, + B_B2, + B_B3, + /** + * Must be last for serialization purposes + */ + B_Sentinel, +}; +typedef uint8_t B; + +enum C_Tag { + C_C1, + C_C2, + C_C3, + /** + * Must be last for serialization purposes + */ + C_Sentinel, +}; +typedef uint8_t C_Tag; + +struct C_C1_Body { + C_Tag tag; + uint32_t a; +}; + +struct C_C2_Body { + C_Tag tag; + uint32_t b; +}; + +union C { + enum C_Tag tag; + struct C_C1_Body c1; + struct C_C2_Body c2; +}; + +void root(A a, B b, union C c); diff --git a/tests/expectations/tag/sentinel.compat.c b/tests/expectations/tag/sentinel.compat.c new file mode 100644 index 000000000..828bbcc46 --- /dev/null +++ b/tests/expectations/tag/sentinel.compat.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include + +enum A +#ifdef __cplusplus + : uint8_t +#endif // __cplusplus + { + A_A1, + A_A2, + A_A3, + /** + * Must be last for serialization purposes + */ + A_Sentinel, +}; +#ifndef __cplusplus +typedef uint8_t A; +#endif // __cplusplus + +enum B +#ifdef __cplusplus + : uint8_t +#endif // __cplusplus + { + B_B1, + B_B2, + B_B3, + /** + * Must be last for serialization purposes + */ + B_Sentinel, +}; +#ifndef __cplusplus +typedef uint8_t B; +#endif // __cplusplus + +enum C_Tag +#ifdef __cplusplus + : uint8_t +#endif // __cplusplus + { + C_C1, + C_C2, + C_C3, + /** + * Must be last for serialization purposes + */ + C_Sentinel, +}; +#ifndef __cplusplus +typedef uint8_t C_Tag; +#endif // __cplusplus + +struct C_C1_Body { + C_Tag tag; + uint32_t a; +}; + +struct C_C2_Body { + C_Tag tag; + uint32_t b; +}; + +union C { + enum C_Tag tag; + struct C_C1_Body c1; + struct C_C2_Body c2; +}; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root(A a, B b, union C c); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/rust/sentinel.rs b/tests/rust/sentinel.rs new file mode 100644 index 000000000..601b6ee62 --- /dev/null +++ b/tests/rust/sentinel.rs @@ -0,0 +1,23 @@ +#[repr(u8)] +pub enum A { + A1, + A2, + A3, +} + +#[repr(u8)] +pub enum B { + B1, + B2, + B3, +} + +#[repr(u8)] +pub enum C { + C1 { a: u32 }, + C2 { b: u32 }, + C3, +} + +#[no_mangle] +pub extern "C" fn root(a: A, b: B, c: C) {} diff --git a/tests/rust/sentinel.toml b/tests/rust/sentinel.toml new file mode 100644 index 000000000..281803f97 --- /dev/null +++ b/tests/rust/sentinel.toml @@ -0,0 +1,3 @@ +[enum] +add_sentinel = true +prefix_with_name = true