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

Allow more constexpr constants. #756

Merged
merged 3 commits into from Apr 21, 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
6 changes: 6 additions & 0 deletions CHANGES
@@ -1,3 +1,9 @@
## 0.23.0

* Better support for constexpr. (#756)
* constexpr is now enabled by default in C++ mode. You can use const.allow_constexpr=false to revert to previous behavior. (#756)
* Minimum syn version no longer parses old rust code. (#754)

## 0.22.0

* Support rename rule for union body members (#751).
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.22.0"
version = "0.23.0"
authors = [
"Emilio Cobos Álvarez <emilio@crisal.io>",
"Jeff Muizelaar <jmuizelaar@mozilla.com>",
Expand Down
2 changes: 1 addition & 1 deletion docs.md
Expand Up @@ -913,7 +913,7 @@ allow_static_const = true

# Whether a generated constant can be constexpr in C++ mode.
#
# default: false
# default: true
allow_constexpr = false

# This rule specifies the order in which constants will be sorted.
Expand Down
2 changes: 1 addition & 1 deletion src/bindgen/config.rs
Expand Up @@ -706,7 +706,7 @@ impl Default for ConstantConfig {
fn default() -> ConstantConfig {
ConstantConfig {
allow_static_const: true,
allow_constexpr: false,
allow_constexpr: true,
sort_by: None,
}
}
Expand Down
59 changes: 46 additions & 13 deletions src/bindgen/ir/constant.rs
Expand Up @@ -183,22 +183,60 @@ impl Literal {
}
}

pub fn uses_only_primitive_types(&self) -> bool {
fn can_be_constexpr(&self) -> bool {
!self.has_pointer_casts()
}

fn visit(&self, visitor: &mut impl FnMut(&Self) -> bool) -> bool {
if !visitor(self) {
return false;
}
match self {
Literal::Expr(..) | Literal::Path { .. } => true,
Literal::PostfixUnaryOp { ref value, .. } => value.uses_only_primitive_types(),
Literal::PostfixUnaryOp { ref value, .. } => value.visit(visitor),
Literal::BinOp {
ref left,
ref right,
..
} => left.uses_only_primitive_types() & right.uses_only_primitive_types(),
Literal::FieldAccess { ref base, .. } => base.uses_only_primitive_types(),
Literal::Struct { .. } => false,
Literal::Cast { ref value, ref ty } => {
value.uses_only_primitive_types() && ty.is_primitive_or_ptr_primitive()
} => left.visit(visitor) && right.visit(visitor),
Literal::FieldAccess { ref base, .. } => base.visit(visitor),
Literal::Struct { ref fields, .. } => {
for (_name, field) in fields.iter() {
if !field.visit(visitor) {
return false;
}
}
true
}
Literal::Cast { ref value, .. } => value.visit(visitor),
}
}

fn has_pointer_casts(&self) -> bool {
let mut has_pointer_casts = false;
self.visit(&mut |lit| {
if let Literal::Cast { ref ty, .. } = *lit {
has_pointer_casts = has_pointer_casts || ty.is_ptr();
}
!has_pointer_casts
});
has_pointer_casts
}

pub fn uses_only_primitive_types(&self) -> bool {
let mut uses_only_primitive_types = true;
self.visit(&mut |lit| {
// XXX This is a bit sketchy, but alas.
uses_only_primitive_types = uses_only_primitive_types
&& match *lit {
Literal::Struct { .. } => false,
Literal::Cast { ref ty, .. } => ty.is_primitive_or_ptr_primitive(),
_ => true,
};
uses_only_primitive_types
});
uses_only_primitive_types
}
}

impl Literal {
Expand Down Expand Up @@ -720,12 +758,7 @@ impl Constant {

self.documentation.write(config, out);

let allow_constexpr = if let Type::Primitive(..) = self.ty {
config.constant.allow_constexpr
} else {
false
};

let allow_constexpr = config.constant.allow_constexpr && self.value.can_be_constexpr();
match config.language {
Language::Cxx if config.constant.allow_static_const || allow_constexpr => {
if allow_constexpr {
Expand Down
4 changes: 4 additions & 0 deletions src/bindgen/ir/ty.rs
Expand Up @@ -501,6 +501,10 @@ impl Type {
Ok(Some(converted))
}

pub fn is_ptr(&self) -> bool {
matches!(*self, Type::Ptr { .. } | Type::FuncPtr { .. })
}

pub fn is_primitive_or_ptr_primitive(&self) -> bool {
match *self {
Type::Primitive(..) => true,
Expand Down
2 changes: 1 addition & 1 deletion tests/expectations/assoc_const_conflict.cpp
Expand Up @@ -4,4 +4,4 @@
#include <ostream>
#include <new>

static const uint32_t Foo_FOO = 42;
constexpr static const uint32_t Foo_FOO = 42;
4 changes: 2 additions & 2 deletions tests/expectations/assoc_constant.cpp
Expand Up @@ -7,8 +7,8 @@
struct Foo {

};
static const int32_t Foo_GA = 10;
static const float Foo_ZO = 3.14;
constexpr static const int32_t Foo_GA = 10;
constexpr static const float Foo_ZO = 3.14;

extern "C" {

Expand Down
20 changes: 10 additions & 10 deletions tests/expectations/associated_in_body.cpp
Expand Up @@ -47,26 +47,26 @@ struct StyleAlignFlags {
static const StyleAlignFlags MIXED_SELF;
};
/// 'auto'
inline const StyleAlignFlags StyleAlignFlags::AUTO = StyleAlignFlags{ /* .bits = */ (uint8_t)0 };
constexpr inline const StyleAlignFlags StyleAlignFlags::AUTO = StyleAlignFlags{ /* .bits = */ (uint8_t)0 };
/// 'normal'
inline const StyleAlignFlags StyleAlignFlags::NORMAL = StyleAlignFlags{ /* .bits = */ (uint8_t)1 };
constexpr inline const StyleAlignFlags StyleAlignFlags::NORMAL = StyleAlignFlags{ /* .bits = */ (uint8_t)1 };
/// 'start'
inline const StyleAlignFlags StyleAlignFlags::START = StyleAlignFlags{ /* .bits = */ (uint8_t)(1 << 1) };
constexpr inline const StyleAlignFlags StyleAlignFlags::START = StyleAlignFlags{ /* .bits = */ (uint8_t)(1 << 1) };
/// 'end'
inline const StyleAlignFlags StyleAlignFlags::END = StyleAlignFlags{ /* .bits = */ (uint8_t)(1 << 2) };
inline const StyleAlignFlags StyleAlignFlags::ALIAS = StyleAlignFlags{ /* .bits = */ (uint8_t)(StyleAlignFlags::END).bits };
constexpr inline const StyleAlignFlags StyleAlignFlags::END = StyleAlignFlags{ /* .bits = */ (uint8_t)(1 << 2) };
constexpr inline const StyleAlignFlags StyleAlignFlags::ALIAS = StyleAlignFlags{ /* .bits = */ (uint8_t)(StyleAlignFlags::END).bits };
/// 'flex-start'
inline const StyleAlignFlags StyleAlignFlags::FLEX_START = StyleAlignFlags{ /* .bits = */ (uint8_t)(1 << 3) };
inline const StyleAlignFlags StyleAlignFlags::MIXED = StyleAlignFlags{ /* .bits = */ (uint8_t)(((1 << 4) | (StyleAlignFlags::FLEX_START).bits) | (StyleAlignFlags::END).bits) };
inline const StyleAlignFlags StyleAlignFlags::MIXED_SELF = StyleAlignFlags{ /* .bits = */ (uint8_t)(((1 << 5) | (StyleAlignFlags::FLEX_START).bits) | (StyleAlignFlags::END).bits) };
constexpr inline const StyleAlignFlags StyleAlignFlags::FLEX_START = StyleAlignFlags{ /* .bits = */ (uint8_t)(1 << 3) };
constexpr inline const StyleAlignFlags StyleAlignFlags::MIXED = StyleAlignFlags{ /* .bits = */ (uint8_t)(((1 << 4) | (StyleAlignFlags::FLEX_START).bits) | (StyleAlignFlags::END).bits) };
constexpr inline const StyleAlignFlags StyleAlignFlags::MIXED_SELF = StyleAlignFlags{ /* .bits = */ (uint8_t)(((1 << 5) | (StyleAlignFlags::FLEX_START).bits) | (StyleAlignFlags::END).bits) };

/// An arbitrary identifier for a native (OS compositor) surface
struct StyleNativeSurfaceId {
uint64_t _0;
static const StyleNativeSurfaceId DEBUG_OVERLAY;
};
/// A special id for the native surface that is used for debug / profiler overlays.
inline const StyleNativeSurfaceId StyleNativeSurfaceId::DEBUG_OVERLAY = StyleNativeSurfaceId{ /* ._0 = */ UINT64_MAX };
constexpr inline const StyleNativeSurfaceId StyleNativeSurfaceId::DEBUG_OVERLAY = StyleNativeSurfaceId{ /* ._0 = */ UINT64_MAX };

struct StyleNativeTileId {
StyleNativeSurfaceId surface_id;
Expand All @@ -75,7 +75,7 @@ struct StyleNativeTileId {
static const StyleNativeTileId DEBUG_OVERLAY;
};
/// A special id for the native surface that is used for debug / profiler overlays.
inline const StyleNativeTileId StyleNativeTileId::DEBUG_OVERLAY = StyleNativeTileId{ /* .surface_id = */ StyleNativeSurfaceId::DEBUG_OVERLAY, /* .x = */ 0, /* .y = */ 0 };
constexpr inline const StyleNativeTileId StyleNativeTileId::DEBUG_OVERLAY = StyleNativeTileId{ /* .surface_id = */ StyleNativeSurfaceId::DEBUG_OVERLAY, /* .x = */ 0, /* .y = */ 0 };

extern "C" {

Expand Down
18 changes: 9 additions & 9 deletions tests/expectations/bitflags.cpp
Expand Up @@ -39,18 +39,18 @@ struct AlignFlags {
}
};
/// 'auto'
static const AlignFlags AlignFlags_AUTO = AlignFlags{ /* .bits = */ (uint8_t)0 };
constexpr static const AlignFlags AlignFlags_AUTO = AlignFlags{ /* .bits = */ (uint8_t)0 };
/// 'normal'
static const AlignFlags AlignFlags_NORMAL = AlignFlags{ /* .bits = */ (uint8_t)1 };
constexpr static const AlignFlags AlignFlags_NORMAL = AlignFlags{ /* .bits = */ (uint8_t)1 };
/// 'start'
static const AlignFlags AlignFlags_START = AlignFlags{ /* .bits = */ (uint8_t)(1 << 1) };
constexpr static const AlignFlags AlignFlags_START = AlignFlags{ /* .bits = */ (uint8_t)(1 << 1) };
/// 'end'
static const AlignFlags AlignFlags_END = AlignFlags{ /* .bits = */ (uint8_t)(1 << 2) };
static const AlignFlags AlignFlags_ALIAS = AlignFlags{ /* .bits = */ (uint8_t)(AlignFlags_END).bits };
constexpr static const AlignFlags AlignFlags_END = AlignFlags{ /* .bits = */ (uint8_t)(1 << 2) };
constexpr static const AlignFlags AlignFlags_ALIAS = AlignFlags{ /* .bits = */ (uint8_t)(AlignFlags_END).bits };
/// 'flex-start'
static const AlignFlags AlignFlags_FLEX_START = AlignFlags{ /* .bits = */ (uint8_t)(1 << 3) };
static const AlignFlags AlignFlags_MIXED = AlignFlags{ /* .bits = */ (uint8_t)(((1 << 4) | (AlignFlags_FLEX_START).bits) | (AlignFlags_END).bits) };
static const AlignFlags AlignFlags_MIXED_SELF = AlignFlags{ /* .bits = */ (uint8_t)(((1 << 5) | (AlignFlags_FLEX_START).bits) | (AlignFlags_END).bits) };
constexpr static const AlignFlags AlignFlags_FLEX_START = AlignFlags{ /* .bits = */ (uint8_t)(1 << 3) };
constexpr static const AlignFlags AlignFlags_MIXED = AlignFlags{ /* .bits = */ (uint8_t)(((1 << 4) | (AlignFlags_FLEX_START).bits) | (AlignFlags_END).bits) };
constexpr static const AlignFlags AlignFlags_MIXED_SELF = AlignFlags{ /* .bits = */ (uint8_t)(((1 << 5) | (AlignFlags_FLEX_START).bits) | (AlignFlags_END).bits) };

struct DebugFlags {
uint32_t bits;
Expand Down Expand Up @@ -84,7 +84,7 @@ struct DebugFlags {
}
};
/// Flag with the topmost bit set of the u32
static const DebugFlags DebugFlags_BIGGEST_ALLOWED = DebugFlags{ /* .bits = */ (uint32_t)(1 << 31) };
constexpr static const DebugFlags DebugFlags_BIGGEST_ALLOWED = DebugFlags{ /* .bits = */ (uint32_t)(1 << 31) };

extern "C" {

Expand Down
4 changes: 2 additions & 2 deletions tests/expectations/cfg_2.cpp
Expand Up @@ -11,11 +11,11 @@ DEF NOT_DEFINED = 0
#include <new>

#if defined(NOT_DEFINED)
static const int32_t DEFAULT_X = 8;
constexpr static const int32_t DEFAULT_X = 8;
#endif

#if defined(DEFINED)
static const int32_t DEFAULT_X = 42;
constexpr static const int32_t DEFAULT_X = 42;
#endif

#if (defined(NOT_DEFINED) || defined(DEFINED))
Expand Down
2 changes: 1 addition & 1 deletion tests/expectations/const_conflict.cpp
Expand Up @@ -4,4 +4,4 @@
#include <ostream>
#include <new>

static const uint32_t Foo_FOO = 42;
constexpr static const uint32_t Foo_FOO = 42;
2 changes: 1 addition & 1 deletion tests/expectations/const_transparent.cpp
Expand Up @@ -6,4 +6,4 @@

using Transparent = uint8_t;

static const Transparent FOO = 0;
constexpr static const Transparent FOO = 0;
34 changes: 17 additions & 17 deletions tests/expectations/constant.cpp
Expand Up @@ -4,44 +4,44 @@
#include <ostream>
#include <new>

static const int32_t FOO = 10;
constexpr static const int32_t FOO = 10;

static const uint32_t DELIMITER = ':';
constexpr static const uint32_t DELIMITER = ':';

static const uint32_t LEFTCURLY = '{';
constexpr static const uint32_t LEFTCURLY = '{';

static const uint32_t QUOTE = '\'';
constexpr static const uint32_t QUOTE = '\'';

static const uint32_t TAB = '\t';
constexpr static const uint32_t TAB = '\t';

static const uint32_t NEWLINE = '\n';
constexpr static const uint32_t NEWLINE = '\n';

static const uint32_t HEART = U'\U00002764';
constexpr static const uint32_t HEART = U'\U00002764';

static const uint32_t EQUID = U'\U00010083';
constexpr static const uint32_t EQUID = U'\U00010083';

static const float ZOM = 3.14;
constexpr static const float ZOM = 3.14;

/// A single-line doc comment.
static const int8_t POS_ONE = 1;
constexpr static const int8_t POS_ONE = 1;

/// A
/// multi-line
/// doc
/// comment.
static const int8_t NEG_ONE = -1;
constexpr static const int8_t NEG_ONE = -1;

static const int64_t SHIFT = 3;
constexpr static const int64_t SHIFT = 3;

static const int64_t XBOOL = 1;
constexpr static const int64_t XBOOL = 1;

static const int64_t XFALSE = ((0 << SHIFT) | XBOOL);
constexpr static const int64_t XFALSE = ((0 << SHIFT) | XBOOL);

static const int64_t XTRUE = (1 << (SHIFT | XBOOL));
constexpr static const int64_t XTRUE = (1 << (SHIFT | XBOOL));

static const uint8_t CAST = (uint8_t)'A';
constexpr static const uint8_t CAST = (uint8_t)'A';

static const uint32_t DOUBLE_CAST = (uint32_t)(float)1;
constexpr static const uint32_t DOUBLE_CAST = (uint32_t)(float)1;

struct Foo {
int32_t x[FOO];
Expand Down
8 changes: 4 additions & 4 deletions tests/expectations/constant_big.cpp
Expand Up @@ -4,10 +4,10 @@
#include <ostream>
#include <new>

static const uint64_t UNSIGNED_NEEDS_ULL_SUFFIX = 9223372036854775808ULL;
constexpr static const uint64_t UNSIGNED_NEEDS_ULL_SUFFIX = 9223372036854775808ULL;

static const uint64_t UNSIGNED_DOESNT_NEED_ULL_SUFFIX = 8070450532247928832;
constexpr static const uint64_t UNSIGNED_DOESNT_NEED_ULL_SUFFIX = 8070450532247928832;

static const int64_t SIGNED_NEEDS_ULL_SUFFIX = -9223372036854775808ULL;
constexpr static const int64_t SIGNED_NEEDS_ULL_SUFFIX = -9223372036854775808ULL;

static const int64_t SIGNED_DOESNT_NEED_ULL_SUFFIX = -9223372036854775807;
constexpr static const int64_t SIGNED_DOESNT_NEED_ULL_SUFFIX = -9223372036854775807;
10 changes: 5 additions & 5 deletions tests/expectations/constant_constexpr.cpp
Expand Up @@ -4,18 +4,18 @@
#include <ostream>
#include <new>

constexpr static const int64_t CONSTANT_I64 = 216;
static const int64_t CONSTANT_I64 = 216;

constexpr static const float CONSTANT_FLOAT32 = 312.292;
static const float CONSTANT_FLOAT32 = 312.292;

constexpr static const uint32_t DELIMITER = ':';
static const uint32_t DELIMITER = ':';

constexpr static const uint32_t LEFTCURLY = '{';
static const uint32_t LEFTCURLY = '{';

struct Foo {
int32_t x;
static const int64_t CONSTANT_I64_BODY;
};
constexpr inline const int64_t Foo::CONSTANT_I64_BODY = 216;
inline const int64_t Foo::CONSTANT_I64_BODY = 216;

static const Foo SomeFoo = Foo{ /* .x = */ 99 };
4 changes: 2 additions & 2 deletions tests/expectations/constant_sort_name.cpp
Expand Up @@ -4,9 +4,9 @@
#include <ostream>
#include <new>

static const uint8_t A = 0;
constexpr static const uint8_t A = 0;

static const uint8_t B = 0;
constexpr static const uint8_t B = 0;

extern "C" {

Expand Down
4 changes: 2 additions & 2 deletions tests/expectations/constant_sort_none.cpp
Expand Up @@ -4,9 +4,9 @@
#include <ostream>
#include <new>

static const uint8_t B = 0;
constexpr static const uint8_t B = 0;

static const uint8_t A = 0;
constexpr static const uint8_t A = 0;

extern "C" {

Expand Down
6 changes: 3 additions & 3 deletions tests/expectations/constant_user_defined_type.cpp
Expand Up @@ -14,8 +14,8 @@ struct S {

using A = uint8_t;

static const S C1 = S{ /* .field = */ 0 };
constexpr static const S C1 = S{ /* .field = */ 0 };

static const E C2 = V;
constexpr static const E C2 = V;

static const A C3 = 0;
constexpr static const A C3 = 0;