From a94d6e2c9b486b423436ea692d9700fc0c06a00d Mon Sep 17 00:00:00 2001 From: mexus Date: Fri, 24 Jul 2020 16:44:19 +0300 Subject: [PATCH] Support "never" return type --- src/bindgen/config.rs | 3 +++ src/bindgen/ir/function.rs | 22 ++++++++++++++++- tests/expectations/both/fns.c | 2 ++ tests/expectations/both/fns.compat.c | 2 ++ tests/expectations/both/function_noreturn.c | 16 +++++++++++++ .../both/function_noreturn.compat.c | 24 +++++++++++++++++++ tests/expectations/fns.c | 2 ++ tests/expectations/fns.compat.c | 2 ++ tests/expectations/fns.cpp | 2 ++ tests/expectations/function_noreturn.c | 16 +++++++++++++ tests/expectations/function_noreturn.compat.c | 24 +++++++++++++++++++ tests/expectations/function_noreturn.cpp | 20 ++++++++++++++++ tests/expectations/tag/fns.c | 2 ++ tests/expectations/tag/fns.compat.c | 2 ++ tests/expectations/tag/function_noreturn.c | 16 +++++++++++++ .../tag/function_noreturn.compat.c | 24 +++++++++++++++++++ tests/rust/fns.rs | 5 ++++ tests/rust/function_noreturn.rs | 9 +++++++ tests/rust/function_noreturn.toml | 12 ++++++++++ 19 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 tests/expectations/both/function_noreturn.c create mode 100644 tests/expectations/both/function_noreturn.compat.c create mode 100644 tests/expectations/function_noreturn.c create mode 100644 tests/expectations/function_noreturn.compat.c create mode 100644 tests/expectations/function_noreturn.cpp create mode 100644 tests/expectations/tag/function_noreturn.c create mode 100644 tests/expectations/tag/function_noreturn.compat.c create mode 100644 tests/rust/function_noreturn.rs create mode 100644 tests/rust/function_noreturn.toml diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index 580c9e0..eed84c5 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -317,6 +317,8 @@ pub struct FunctionConfig { pub swift_name_macro: Option, /// Sort key for function names pub sort_by: SortKey, + /// Optional text to output after functions which return `!`. + pub no_return: Option, } impl Default for FunctionConfig { @@ -329,6 +331,7 @@ impl Default for FunctionConfig { rename_args: None, swift_name_macro: None, sort_by: SortKey::Name, + no_return: None, } } } diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index bdf0ecc..24d9861 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -33,6 +33,7 @@ pub struct Function { pub cfg: Option, pub annotations: AnnotationSet, pub documentation: Documentation, + pub never_return: bool, } impl Function { @@ -46,10 +47,16 @@ impl Function { ) -> Result { let mut args = sig.inputs.iter().try_skip_map(|x| x.as_ident_and_type())?; + let mut never_return = false; let mut ret = match sig.output { syn::ReturnType::Default => Type::Primitive(PrimitiveType::Void), syn::ReturnType::Type(_, ref ty) => { - Type::load(ty)?.unwrap_or_else(|| Type::Primitive(PrimitiveType::Void)) + if let syn::Type::Never(_) = ty.as_ref() { + never_return = true; + Type::Primitive(PrimitiveType::Void) + } else { + Type::load(ty)?.unwrap_or_else(|| Type::Primitive(PrimitiveType::Void)) + } } }; @@ -69,6 +76,7 @@ impl Function { cfg: Cfg::append(mod_cfg, Cfg::load(attrs)), annotations: AnnotationSet::load(attrs)?, documentation: Documentation::load(attrs), + never_return, }) } @@ -205,6 +213,12 @@ impl Source for Function { write!(out, " {}({})", swift_name_macro, func.swift_name()); } + if func.never_return { + if let Some(ref no_return_attr) = config.function.no_return { + out.write_fmt(format_args!(" {}", no_return_attr)); + } + } + out.write(";"); condition.write_after(config, out); @@ -246,6 +260,12 @@ impl Source for Function { write!(out, " {}({})", swift_name_macro, func.swift_name()); } + if func.never_return { + if let Some(ref no_return_attr) = config.function.no_return { + out.write_fmt(format_args!(" {}", no_return_attr)); + } + } + out.write(";"); condition.write_after(config, out); diff --git a/tests/expectations/both/fns.c b/tests/expectations/both/fns.c index edc2d71..715cc49 100644 --- a/tests/expectations/both/fns.c +++ b/tests/expectations/both/fns.c @@ -11,4 +11,6 @@ typedef struct Fns { int8_t (*namedArgsWildcards)(int32_t _, int16_t named, int64_t _1); } Fns; +void no_return(void); + void root(Fns _fns); diff --git a/tests/expectations/both/fns.compat.c b/tests/expectations/both/fns.compat.c index 66c521f..d203651 100644 --- a/tests/expectations/both/fns.compat.c +++ b/tests/expectations/both/fns.compat.c @@ -15,6 +15,8 @@ typedef struct Fns { extern "C" { #endif // __cplusplus +void no_return(void); + void root(Fns _fns); #ifdef __cplusplus diff --git a/tests/expectations/both/function_noreturn.c b/tests/expectations/both/function_noreturn.c new file mode 100644 index 0000000..e715ae3 --- /dev/null +++ b/tests/expectations/both/function_noreturn.c @@ -0,0 +1,16 @@ +#include +#include +#include +#include +#ifndef NO_RETURN_ATTR + #ifdef __GNUC__ + #define NO_RETURN_ATTR __attribute__ ((noreturn)) + #else // __GNUC__ + #define NO_RETURN_ATTR + #endif // __GNUC__ +#endif // NO_RETURN_ATTR + + +void loop_forever(void) NO_RETURN_ATTR; + +uint8_t normal_return(void); diff --git a/tests/expectations/both/function_noreturn.compat.c b/tests/expectations/both/function_noreturn.compat.c new file mode 100644 index 0000000..12238b3 --- /dev/null +++ b/tests/expectations/both/function_noreturn.compat.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include +#ifndef NO_RETURN_ATTR + #ifdef __GNUC__ + #define NO_RETURN_ATTR __attribute__ ((noreturn)) + #else // __GNUC__ + #define NO_RETURN_ATTR + #endif // __GNUC__ +#endif // NO_RETURN_ATTR + + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void loop_forever(void) NO_RETURN_ATTR; + +uint8_t normal_return(void); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/fns.c b/tests/expectations/fns.c index 1c599b7..ad86f93 100644 --- a/tests/expectations/fns.c +++ b/tests/expectations/fns.c @@ -11,4 +11,6 @@ typedef struct { int8_t (*namedArgsWildcards)(int32_t _, int16_t named, int64_t _1); } Fns; +void no_return(void); + void root(Fns _fns); diff --git a/tests/expectations/fns.compat.c b/tests/expectations/fns.compat.c index 6303a37..4000b21 100644 --- a/tests/expectations/fns.compat.c +++ b/tests/expectations/fns.compat.c @@ -15,6 +15,8 @@ typedef struct { extern "C" { #endif // __cplusplus +void no_return(void); + void root(Fns _fns); #ifdef __cplusplus diff --git a/tests/expectations/fns.cpp b/tests/expectations/fns.cpp index e5bdea2..8ee753a 100644 --- a/tests/expectations/fns.cpp +++ b/tests/expectations/fns.cpp @@ -13,6 +13,8 @@ struct Fns { extern "C" { +void no_return(); + void root(Fns _fns); } // extern "C" diff --git a/tests/expectations/function_noreturn.c b/tests/expectations/function_noreturn.c new file mode 100644 index 0000000..e715ae3 --- /dev/null +++ b/tests/expectations/function_noreturn.c @@ -0,0 +1,16 @@ +#include +#include +#include +#include +#ifndef NO_RETURN_ATTR + #ifdef __GNUC__ + #define NO_RETURN_ATTR __attribute__ ((noreturn)) + #else // __GNUC__ + #define NO_RETURN_ATTR + #endif // __GNUC__ +#endif // NO_RETURN_ATTR + + +void loop_forever(void) NO_RETURN_ATTR; + +uint8_t normal_return(void); diff --git a/tests/expectations/function_noreturn.compat.c b/tests/expectations/function_noreturn.compat.c new file mode 100644 index 0000000..12238b3 --- /dev/null +++ b/tests/expectations/function_noreturn.compat.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include +#ifndef NO_RETURN_ATTR + #ifdef __GNUC__ + #define NO_RETURN_ATTR __attribute__ ((noreturn)) + #else // __GNUC__ + #define NO_RETURN_ATTR + #endif // __GNUC__ +#endif // NO_RETURN_ATTR + + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void loop_forever(void) NO_RETURN_ATTR; + +uint8_t normal_return(void); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/function_noreturn.cpp b/tests/expectations/function_noreturn.cpp new file mode 100644 index 0000000..910ebd3 --- /dev/null +++ b/tests/expectations/function_noreturn.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#ifndef NO_RETURN_ATTR + #ifdef __GNUC__ + #define NO_RETURN_ATTR __attribute__ ((noreturn)) + #else // __GNUC__ + #define NO_RETURN_ATTR + #endif // __GNUC__ +#endif // NO_RETURN_ATTR + + +extern "C" { + +void loop_forever() NO_RETURN_ATTR; + +uint8_t normal_return(); + +} // extern "C" diff --git a/tests/expectations/tag/fns.c b/tests/expectations/tag/fns.c index bf41def..63b2a5e 100644 --- a/tests/expectations/tag/fns.c +++ b/tests/expectations/tag/fns.c @@ -11,4 +11,6 @@ struct Fns { int8_t (*namedArgsWildcards)(int32_t _, int16_t named, int64_t _1); }; +void no_return(void); + void root(struct Fns _fns); diff --git a/tests/expectations/tag/fns.compat.c b/tests/expectations/tag/fns.compat.c index 5e45212..ecf0cb0 100644 --- a/tests/expectations/tag/fns.compat.c +++ b/tests/expectations/tag/fns.compat.c @@ -15,6 +15,8 @@ struct Fns { extern "C" { #endif // __cplusplus +void no_return(void); + void root(struct Fns _fns); #ifdef __cplusplus diff --git a/tests/expectations/tag/function_noreturn.c b/tests/expectations/tag/function_noreturn.c new file mode 100644 index 0000000..e715ae3 --- /dev/null +++ b/tests/expectations/tag/function_noreturn.c @@ -0,0 +1,16 @@ +#include +#include +#include +#include +#ifndef NO_RETURN_ATTR + #ifdef __GNUC__ + #define NO_RETURN_ATTR __attribute__ ((noreturn)) + #else // __GNUC__ + #define NO_RETURN_ATTR + #endif // __GNUC__ +#endif // NO_RETURN_ATTR + + +void loop_forever(void) NO_RETURN_ATTR; + +uint8_t normal_return(void); diff --git a/tests/expectations/tag/function_noreturn.compat.c b/tests/expectations/tag/function_noreturn.compat.c new file mode 100644 index 0000000..12238b3 --- /dev/null +++ b/tests/expectations/tag/function_noreturn.compat.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include +#ifndef NO_RETURN_ATTR + #ifdef __GNUC__ + #define NO_RETURN_ATTR __attribute__ ((noreturn)) + #else // __GNUC__ + #define NO_RETURN_ATTR + #endif // __GNUC__ +#endif // NO_RETURN_ATTR + + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void loop_forever(void) NO_RETURN_ATTR; + +uint8_t normal_return(void); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/rust/fns.rs b/tests/rust/fns.rs index 0b2bb5e..39c5622 100644 --- a/tests/rust/fns.rs +++ b/tests/rust/fns.rs @@ -9,3 +9,8 @@ pub struct Fns { #[no_mangle] pub extern "C" fn root(_fns: Fns) {} + +#[no_mangle] +pub extern "C" fn no_return() -> ! { + loop {} +} diff --git a/tests/rust/function_noreturn.rs b/tests/rust/function_noreturn.rs new file mode 100644 index 0000000..94a2395 --- /dev/null +++ b/tests/rust/function_noreturn.rs @@ -0,0 +1,9 @@ +#[no_mangle] +pub extern fn loop_forever() -> ! { + loop {} +} + +#[no_mangle] +pub extern fn normal_return() -> u8 { + 0 +} diff --git a/tests/rust/function_noreturn.toml b/tests/rust/function_noreturn.toml new file mode 100644 index 0000000..33e88c2 --- /dev/null +++ b/tests/rust/function_noreturn.toml @@ -0,0 +1,12 @@ +after_includes = """ +#ifndef NO_RETURN_ATTR + #ifdef __GNUC__ + #define NO_RETURN_ATTR __attribute__ ((noreturn)) + #else // __GNUC__ + #define NO_RETURN_ATTR + #endif // __GNUC__ +#endif // NO_RETURN_ATTR +""" + +[fn] +no_return = "NO_RETURN_ATTR"