diff --git a/CHANGES b/CHANGES index 2cba7f71d..2579deb9d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +## 0.24.1 + + * Add support for unary negation (#765). + * Make more bitfield operators constexpr (#765). + ## 0.24.0 * Basic const generic support (#759, #760 #762). diff --git a/Cargo.lock b/Cargo.lock index 7a6e0779c..3593ee5b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,7 +27,7 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "cbindgen" -version = "0.24.0" +version = "0.24.1" dependencies = [ "clap", "heck", diff --git a/Cargo.toml b/Cargo.toml index 4174d4bab..f89c4f6e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cbindgen" -version = "0.24.0" +version = "0.24.1" authors = [ "Emilio Cobos Álvarez ", "Jeff Muizelaar ", diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index c181c3461..42182ab92 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -417,6 +417,13 @@ impl Literal { syn::Expr::Unary(syn::ExprUnary { ref op, ref expr, .. }) => match *op { + UnOp::Not(_) => { + let val = Self::load(expr)?; + Ok(Literal::PostfixUnaryOp { + op: "~", + value: Box::new(val), + }) + } UnOp::Neg(_) => { let val = Self::load(expr)?; Ok(Literal::PostfixUnaryOp { diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index be199739d..3db3e7a48 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -205,6 +205,7 @@ impl Struct { fn emit_bitflags_binop( &self, + constexpr_prefix: &str, operator: char, other: &str, out: &mut SourceWriter, @@ -212,7 +213,8 @@ impl Struct { out.new_line(); write!( out, - "{} operator{}(const {}& {}) const", + "{}{} operator{}(const {}& {}) const", + constexpr_prefix, self.export_name(), operator, self.export_name(), @@ -531,21 +533,31 @@ impl Source for Struct { wrote_start_newline = true; out.new_line(); } + let constexpr_prefix = if config.constant.allow_constexpr { + "constexpr " + } else { + "" + }; + out.new_line(); - write!(out, "explicit operator bool() const"); + write!(out, "{}explicit operator bool() const", constexpr_prefix); out.open_brace(); write!(out, "return !!bits;"); out.close_brace(false); out.new_line(); - write!(out, "{} operator~() const", self.export_name()); + write!( + out, + "{}{} operator~() const", + constexpr_prefix, + self.export_name() + ); out.open_brace(); write!(out, "return {{static_cast(~bits)}};"); out.close_brace(false); - - self.emit_bitflags_binop('|', &other, out); - self.emit_bitflags_binop('&', &other, out); - self.emit_bitflags_binop('^', &other, out); + self.emit_bitflags_binop(constexpr_prefix, '|', &other, out); + self.emit_bitflags_binop(constexpr_prefix, '&', &other, out); + self.emit_bitflags_binop(constexpr_prefix, '^', &other, out); } // Generate a serializer function that allows dumping this struct diff --git a/tests/expectations/associated_in_body.cpp b/tests/expectations/associated_in_body.cpp index 14c59e39c..d1319efb4 100644 --- a/tests/expectations/associated_in_body.cpp +++ b/tests/expectations/associated_in_body.cpp @@ -10,27 +10,27 @@ struct StyleAlignFlags { uint8_t bits; - explicit operator bool() const { + constexpr explicit operator bool() const { return !!bits; } - StyleAlignFlags operator~() const { + constexpr StyleAlignFlags operator~() const { return {static_cast(~bits)}; } - StyleAlignFlags operator|(const StyleAlignFlags& other) const { + constexpr StyleAlignFlags operator|(const StyleAlignFlags& other) const { return {static_cast(this->bits | other.bits)}; } StyleAlignFlags& operator|=(const StyleAlignFlags& other) { *this = (*this | other); return *this; } - StyleAlignFlags operator&(const StyleAlignFlags& other) const { + constexpr StyleAlignFlags operator&(const StyleAlignFlags& other) const { return {static_cast(this->bits & other.bits)}; } StyleAlignFlags& operator&=(const StyleAlignFlags& other) { *this = (*this & other); return *this; } - StyleAlignFlags operator^(const StyleAlignFlags& other) const { + constexpr StyleAlignFlags operator^(const StyleAlignFlags& other) const { return {static_cast(this->bits ^ other.bits)}; } StyleAlignFlags& operator^=(const StyleAlignFlags& other) { diff --git a/tests/expectations/bitflags.both.c b/tests/expectations/bitflags.both.c index 6003cfdad..b5cb6a7cf 100644 --- a/tests/expectations/bitflags.both.c +++ b/tests/expectations/bitflags.both.c @@ -50,5 +50,6 @@ typedef struct LargeFlags { * Flag with a very large shift that usually would be narrowed. */ #define LargeFlags_LARGE_SHIFT (LargeFlags){ .bits = (uint64_t)(1ull << 44) } +#define LargeFlags_INVERTED (LargeFlags){ .bits = (uint64_t)~(LargeFlags_LARGE_SHIFT).bits } void root(struct AlignFlags flags, struct DebugFlags bigger_flags, struct LargeFlags largest_flags); diff --git a/tests/expectations/bitflags.both.compat.c b/tests/expectations/bitflags.both.compat.c index e5b560bba..35726624c 100644 --- a/tests/expectations/bitflags.both.compat.c +++ b/tests/expectations/bitflags.both.compat.c @@ -50,6 +50,7 @@ typedef struct LargeFlags { * Flag with a very large shift that usually would be narrowed. */ #define LargeFlags_LARGE_SHIFT (LargeFlags){ .bits = (uint64_t)(1ull << 44) } +#define LargeFlags_INVERTED (LargeFlags){ .bits = (uint64_t)~(LargeFlags_LARGE_SHIFT).bits } #ifdef __cplusplus extern "C" { diff --git a/tests/expectations/bitflags.c b/tests/expectations/bitflags.c index f8148db97..9af76af44 100644 --- a/tests/expectations/bitflags.c +++ b/tests/expectations/bitflags.c @@ -50,5 +50,6 @@ typedef struct { * Flag with a very large shift that usually would be narrowed. */ #define LargeFlags_LARGE_SHIFT (LargeFlags){ .bits = (uint64_t)(1ull << 44) } +#define LargeFlags_INVERTED (LargeFlags){ .bits = (uint64_t)~(LargeFlags_LARGE_SHIFT).bits } void root(AlignFlags flags, DebugFlags bigger_flags, LargeFlags largest_flags); diff --git a/tests/expectations/bitflags.compat.c b/tests/expectations/bitflags.compat.c index 84b38e356..863de08b1 100644 --- a/tests/expectations/bitflags.compat.c +++ b/tests/expectations/bitflags.compat.c @@ -50,6 +50,7 @@ typedef struct { * Flag with a very large shift that usually would be narrowed. */ #define LargeFlags_LARGE_SHIFT (LargeFlags){ .bits = (uint64_t)(1ull << 44) } +#define LargeFlags_INVERTED (LargeFlags){ .bits = (uint64_t)~(LargeFlags_LARGE_SHIFT).bits } #ifdef __cplusplus extern "C" { diff --git a/tests/expectations/bitflags.cpp b/tests/expectations/bitflags.cpp index c77100613..9df48b696 100644 --- a/tests/expectations/bitflags.cpp +++ b/tests/expectations/bitflags.cpp @@ -10,27 +10,27 @@ struct AlignFlags { uint8_t bits; - explicit operator bool() const { + constexpr explicit operator bool() const { return !!bits; } - AlignFlags operator~() const { + constexpr AlignFlags operator~() const { return {static_cast(~bits)}; } - AlignFlags operator|(const AlignFlags& other) const { + constexpr AlignFlags operator|(const AlignFlags& other) const { return {static_cast(this->bits | other.bits)}; } AlignFlags& operator|=(const AlignFlags& other) { *this = (*this | other); return *this; } - AlignFlags operator&(const AlignFlags& other) const { + constexpr AlignFlags operator&(const AlignFlags& other) const { return {static_cast(this->bits & other.bits)}; } AlignFlags& operator&=(const AlignFlags& other) { *this = (*this & other); return *this; } - AlignFlags operator^(const AlignFlags& other) const { + constexpr AlignFlags operator^(const AlignFlags& other) const { return {static_cast(this->bits ^ other.bits)}; } AlignFlags& operator^=(const AlignFlags& other) { @@ -55,27 +55,27 @@ constexpr static const AlignFlags AlignFlags_MIXED_SELF = AlignFlags{ /* .bits = struct DebugFlags { uint32_t bits; - explicit operator bool() const { + constexpr explicit operator bool() const { return !!bits; } - DebugFlags operator~() const { + constexpr DebugFlags operator~() const { return {static_cast(~bits)}; } - DebugFlags operator|(const DebugFlags& other) const { + constexpr DebugFlags operator|(const DebugFlags& other) const { return {static_cast(this->bits | other.bits)}; } DebugFlags& operator|=(const DebugFlags& other) { *this = (*this | other); return *this; } - DebugFlags operator&(const DebugFlags& other) const { + constexpr DebugFlags operator&(const DebugFlags& other) const { return {static_cast(this->bits & other.bits)}; } DebugFlags& operator&=(const DebugFlags& other) { *this = (*this & other); return *this; } - DebugFlags operator^(const DebugFlags& other) const { + constexpr DebugFlags operator^(const DebugFlags& other) const { return {static_cast(this->bits ^ other.bits)}; } DebugFlags& operator^=(const DebugFlags& other) { @@ -89,27 +89,27 @@ constexpr static const DebugFlags DebugFlags_BIGGEST_ALLOWED = DebugFlags{ /* .b struct LargeFlags { uint64_t bits; - explicit operator bool() const { + constexpr explicit operator bool() const { return !!bits; } - LargeFlags operator~() const { + constexpr LargeFlags operator~() const { return {static_cast(~bits)}; } - LargeFlags operator|(const LargeFlags& other) const { + constexpr LargeFlags operator|(const LargeFlags& other) const { return {static_cast(this->bits | other.bits)}; } LargeFlags& operator|=(const LargeFlags& other) { *this = (*this | other); return *this; } - LargeFlags operator&(const LargeFlags& other) const { + constexpr LargeFlags operator&(const LargeFlags& other) const { return {static_cast(this->bits & other.bits)}; } LargeFlags& operator&=(const LargeFlags& other) { *this = (*this & other); return *this; } - LargeFlags operator^(const LargeFlags& other) const { + constexpr LargeFlags operator^(const LargeFlags& other) const { return {static_cast(this->bits ^ other.bits)}; } LargeFlags& operator^=(const LargeFlags& other) { @@ -119,6 +119,7 @@ struct LargeFlags { }; /// Flag with a very large shift that usually would be narrowed. constexpr static const LargeFlags LargeFlags_LARGE_SHIFT = LargeFlags{ /* .bits = */ (uint64_t)(1ull << 44) }; +constexpr static const LargeFlags LargeFlags_INVERTED = LargeFlags{ /* .bits = */ (uint64_t)~(LargeFlags_LARGE_SHIFT).bits }; extern "C" { diff --git a/tests/expectations/bitflags.pyx b/tests/expectations/bitflags.pyx index 68639f8b5..e3d104015 100644 --- a/tests/expectations/bitflags.pyx +++ b/tests/expectations/bitflags.pyx @@ -34,5 +34,6 @@ cdef extern from *: uint64_t bits; # Flag with a very large shift that usually would be narrowed. const LargeFlags LargeFlags_LARGE_SHIFT # = { (1ull << 44) } + const LargeFlags LargeFlags_INVERTED # = { ~(LargeFlags_LARGE_SHIFT).bits } void root(AlignFlags flags, DebugFlags bigger_flags, LargeFlags largest_flags); diff --git a/tests/expectations/bitflags.tag.c b/tests/expectations/bitflags.tag.c index 0492d1205..c4be368d0 100644 --- a/tests/expectations/bitflags.tag.c +++ b/tests/expectations/bitflags.tag.c @@ -50,5 +50,6 @@ struct LargeFlags { * Flag with a very large shift that usually would be narrowed. */ #define LargeFlags_LARGE_SHIFT (LargeFlags){ .bits = (uint64_t)(1ull << 44) } +#define LargeFlags_INVERTED (LargeFlags){ .bits = (uint64_t)~(LargeFlags_LARGE_SHIFT).bits } void root(struct AlignFlags flags, struct DebugFlags bigger_flags, struct LargeFlags largest_flags); diff --git a/tests/expectations/bitflags.tag.compat.c b/tests/expectations/bitflags.tag.compat.c index 52c1e8de7..d12ba40f3 100644 --- a/tests/expectations/bitflags.tag.compat.c +++ b/tests/expectations/bitflags.tag.compat.c @@ -50,6 +50,7 @@ struct LargeFlags { * Flag with a very large shift that usually would be narrowed. */ #define LargeFlags_LARGE_SHIFT (LargeFlags){ .bits = (uint64_t)(1ull << 44) } +#define LargeFlags_INVERTED (LargeFlags){ .bits = (uint64_t)~(LargeFlags_LARGE_SHIFT).bits } #ifdef __cplusplus extern "C" { diff --git a/tests/expectations/bitflags.tag.pyx b/tests/expectations/bitflags.tag.pyx index ba2d37f78..d5f2df6d5 100644 --- a/tests/expectations/bitflags.tag.pyx +++ b/tests/expectations/bitflags.tag.pyx @@ -34,5 +34,6 @@ cdef extern from *: uint64_t bits; # Flag with a very large shift that usually would be narrowed. const LargeFlags LargeFlags_LARGE_SHIFT # = { (1ull << 44) } + const LargeFlags LargeFlags_INVERTED # = { ~(LargeFlags_LARGE_SHIFT).bits } void root(AlignFlags flags, DebugFlags bigger_flags, LargeFlags largest_flags); diff --git a/tests/rust/bitflags.rs b/tests/rust/bitflags.rs index 4d05cb08f..7e78bd815 100644 --- a/tests/rust/bitflags.rs +++ b/tests/rust/bitflags.rs @@ -34,6 +34,7 @@ bitflags! { pub struct LargeFlags: u64 { /// Flag with a very large shift that usually would be narrowed. const LARGE_SHIFT = 1u64 << 44; + const INVERTED = !Self::LARGE_SHIFT.bits; } }