Skip to content

Commit

Permalink
constant: Allow more constexpr constants.
Browse files Browse the repository at this point in the history
  • Loading branch information
emilio committed Apr 21, 2022
1 parent a0ab624 commit 15e1131
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 33 deletions.
59 changes: 46 additions & 13 deletions src/bindgen/ir/constant.rs
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
20 changes: 10 additions & 10 deletions tests/expectations/associated_in_body.cpp
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
2 changes: 1 addition & 1 deletion tests/expectations/constant_constexpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ struct Foo {
};
constexpr inline const int64_t Foo::CONSTANT_I64_BODY = 216;

static const Foo SomeFoo = Foo{ /* .x = */ 99 };
constexpr static const Foo SomeFoo = Foo{ /* .x = */ 99 };
3 changes: 3 additions & 0 deletions tests/rust/associated_in_body.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ bitflags = true

[export]
prefix = "Style" # Just ensuring they play well together :)

[const]
allow_constexpr = true
3 changes: 3 additions & 0 deletions tests/rust/bitflags.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
[macro_expansion]
bitflags = true

[const]
allow_constexpr = true

0 comments on commit 15e1131

Please sign in to comment.