Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More bitflags improvements. #765

Merged
merged 3 commits into from Jun 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions 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).
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "cbindgen"
version = "0.24.0"
version = "0.24.1"
authors = [
"Emilio Cobos Álvarez <emilio@crisal.io>",
"Jeff Muizelaar <jmuizelaar@mozilla.com>",
Expand Down
7 changes: 7 additions & 0 deletions src/bindgen/ir/constant.rs
Expand Up @@ -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 {
Expand Down
26 changes: 19 additions & 7 deletions src/bindgen/ir/structure.rs
Expand Up @@ -205,14 +205,16 @@ impl Struct {

fn emit_bitflags_binop<F: Write>(
&self,
constexpr_prefix: &str,
operator: char,
other: &str,
out: &mut SourceWriter<F>,
) {
out.new_line();
write!(
out,
"{} operator{}(const {}& {}) const",
"{}{} operator{}(const {}& {}) const",
constexpr_prefix,
self.export_name(),
operator,
self.export_name(),
Expand Down Expand Up @@ -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<decltype(bits)>(~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
Expand Down
10 changes: 5 additions & 5 deletions tests/expectations/associated_in_body.cpp
Expand Up @@ -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<decltype(bits)>(~bits)};
}
StyleAlignFlags operator|(const StyleAlignFlags& other) const {
constexpr StyleAlignFlags operator|(const StyleAlignFlags& other) const {
return {static_cast<decltype(bits)>(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<decltype(bits)>(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<decltype(bits)>(this->bits ^ other.bits)};
}
StyleAlignFlags& operator^=(const StyleAlignFlags& other) {
Expand Down
1 change: 1 addition & 0 deletions tests/expectations/bitflags.both.c
Expand Up @@ -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);
1 change: 1 addition & 0 deletions tests/expectations/bitflags.both.compat.c
Expand Up @@ -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" {
Expand Down
1 change: 1 addition & 0 deletions tests/expectations/bitflags.c
Expand Up @@ -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);
1 change: 1 addition & 0 deletions tests/expectations/bitflags.compat.c
Expand Up @@ -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" {
Expand Down
31 changes: 16 additions & 15 deletions tests/expectations/bitflags.cpp
Expand Up @@ -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<decltype(bits)>(~bits)};
}
AlignFlags operator|(const AlignFlags& other) const {
constexpr AlignFlags operator|(const AlignFlags& other) const {
return {static_cast<decltype(bits)>(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<decltype(bits)>(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<decltype(bits)>(this->bits ^ other.bits)};
}
AlignFlags& operator^=(const AlignFlags& other) {
Expand All @@ -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<decltype(bits)>(~bits)};
}
DebugFlags operator|(const DebugFlags& other) const {
constexpr DebugFlags operator|(const DebugFlags& other) const {
return {static_cast<decltype(bits)>(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<decltype(bits)>(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<decltype(bits)>(this->bits ^ other.bits)};
}
DebugFlags& operator^=(const DebugFlags& other) {
Expand All @@ -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<decltype(bits)>(~bits)};
}
LargeFlags operator|(const LargeFlags& other) const {
constexpr LargeFlags operator|(const LargeFlags& other) const {
return {static_cast<decltype(bits)>(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<decltype(bits)>(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<decltype(bits)>(this->bits ^ other.bits)};
}
LargeFlags& operator^=(const LargeFlags& other) {
Expand All @@ -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" {

Expand Down
1 change: 1 addition & 0 deletions tests/expectations/bitflags.pyx
Expand Up @@ -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 # = <LargeFlags>{ <uint64_t>(1ull << 44) }
const LargeFlags LargeFlags_INVERTED # = <LargeFlags>{ <uint64_t>~(LargeFlags_LARGE_SHIFT).bits }

void root(AlignFlags flags, DebugFlags bigger_flags, LargeFlags largest_flags);
1 change: 1 addition & 0 deletions tests/expectations/bitflags.tag.c
Expand Up @@ -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);
1 change: 1 addition & 0 deletions tests/expectations/bitflags.tag.compat.c
Expand Up @@ -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" {
Expand Down
1 change: 1 addition & 0 deletions tests/expectations/bitflags.tag.pyx
Expand Up @@ -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 # = <LargeFlags>{ <uint64_t>(1ull << 44) }
const LargeFlags LargeFlags_INVERTED # = <LargeFlags>{ <uint64_t>~(LargeFlags_LARGE_SHIFT).bits }

void root(AlignFlags flags, DebugFlags bigger_flags, LargeFlags largest_flags);
1 change: 1 addition & 0 deletions tests/rust/bitflags.rs
Expand Up @@ -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;
}
}

Expand Down