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

Feature 699 constified enum module #741

Merged
Prev Previous commit
Simplify is_constified_enum_module
Used suggested code from @emilio and also added a test for an alias to
an anonymous enum.
  • Loading branch information
tmfink committed Jun 21, 2017
commit 814d28e0f256a24865f633b5992ced6f035d6f4c
58 changes: 22 additions & 36 deletions src/ir/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -829,46 +829,32 @@ impl Item {

/// Returns whether the item is a constified module enum
fn is_constified_enum_module(&self, ctx: &BindgenContext) -> bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So what you're trying to do here is resolving through ResolvedTypeRefs, but not through Alias, right?

If so, instead of reinventing the wheel, you can do something like:

self.id.into_resolver()
    .through_type_refs()
    .resolve(ctx)

And keep the comment on why not through type alias.

We should arguably unify that and the canonical_type business, but that also handles some template stuff that may be nontrivial, so it's worth doing on a followup.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The check needs to "peel back" one layer of Aliases. The issue with the resolve() function is that it resolves through all of the Aliases.

I think that implementation should remain as is.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... I see. I guess I'm not sure why would making an alias claim it's a constified enum module be necessary.

I guess I'll poke a bit at the code this evening when I have the chance and see which tests break with that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... Ok, so what breaks in that case is the typedef enum case... fun. I still think we should be able to do better, though...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about modifying ItemResolver to optionally disable recursive resolving? More generally, ItemResolver could even take a positive integer indicating through how many layers to resolve.

This way, is_constified_enum_module() could be simplified to use ItemResolver.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is about the number of layers to resolve. I think the logic in is_constified_enum_module is wrong, and the "alias to resolved type ref to alias" logic is just masking it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's what I came up with, I think this is what you're really trying to do with that function:

    /// Returns whether the item is a constified module enum.
    fn is_constified_enum_module(&self, ctx: &BindgenContext) -> bool {
        // Do not jump through aliases, except for aliases that point to a type
        // with the same name, since we don't generate code for them.
        let item = self.id.into_resolver().through_type_refs().resolve(ctx);
        let type_ = match *item.kind() {
            ItemKind::Type(ref type_) => type_,
            _ => return false,
        };

        match *type_.kind() {
            TypeKind::Enum(ref enum_) => {
                enum_.is_constified_enum_module(ctx, self)
            }
            TypeKind::Alias(inner) => {
                // TODO(emilio): Make this "hop through type aliases that aren't
                // really generated" an option in `ItemResolver`?
                let inner_item = ctx.resolve_item(inner);
                let name = item.canonical_name(ctx);

                if inner_item.canonical_name(ctx) != name {
                    return false;
                }

                return inner_item.is_constified_enum_module(ctx)
            }
            _ => false,
        }
    }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to address the TODO if you want, btw :)

if let ItemKind::Type(ref type_) = self.kind {
// Do not count an "alias of an alias" as a constified module enum;
// otherwise, we will get:
// pub mod foo {
// pub type Type = ::std::os::raw::c_uint;
// ...
// }
// pub use foo::Type as foo_alias1;
// pub use foo_alias1::Type as foo_alias2;
// pub use foo_alias2::Type as foo_alias3;
// ...
//
// (We do not want the '::Type' appended to the alias types; only the base type)
if let TypeKind::Alias(inner_id) = *type_.kind() {
let inner_item = ctx.resolve_item(inner_id);
if let ItemKind::Type(ref inner_type) = *inner_item.kind() {
match *inner_type.kind() {
TypeKind::Alias(..) => { return false; }
TypeKind::ResolvedTypeRef(resolved_id) => {
// We need to handle:
// Alias -> ResolvedTypeRef -> Alias
let resolved_item = ctx.resolve_item(resolved_id);
if let ItemKind::Type(ref resolved_type) = *resolved_item.kind() {
if let TypeKind::Alias(..) = *resolved_type.kind() {
return false;
}
}
}
_ => (),
}
}
// Do not jump through aliases, except for aliases that point to a type
// with the same name, since we dont generate coe for them.
let item = self.id.into_resolver().through_type_refs().resolve(ctx);
let type_ = match *item.kind() {
ItemKind::Type(ref type_) => type_,
_ => return false,
};

match *type_.kind() {
TypeKind::Enum(ref enum_) => {
enum_.is_constified_enum_module(ctx, self)
}
if let Some(ref type_) = type_.safe_canonical_type(ctx) {
if let TypeKind::Enum(ref enum_) = *type_.kind() {
return enum_.is_constified_enum_module(ctx, self);
TypeKind::Alias(inner_id) => {
// TODO(emilio): Make this "hop through type aliases that aren't
// really generated" an option in `ItemResolver`?
let inner_item = ctx.resolve_item(inner_id);
let name = item.canonical_name(ctx);

if inner_item.canonical_name(ctx) == name {
inner_item.is_constified_enum_module(ctx)
} else {
false
}
}
_ => false,
}

return false;
}
}

Expand Down
35 changes: 34 additions & 1 deletion tests/expectations/tests/constify-module-enums-types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ pub mod foo {
pub const ALSO_THIS: Type = 42;
pub const AND_ALSO_THIS: Type = 42;
}
pub mod anon_enum {
pub type Type = ::std::os::raw::c_uint;
pub const Variant1: Type = 0;
pub const Variant2: Type = 1;
pub const Variant3: Type = 2;
}
pub mod ns1_foo {
pub type Type = ::std::os::raw::c_uint;
pub const THIS: Type = 0;
Expand All @@ -27,6 +33,9 @@ pub mod ns2_Foo {
pub use self::foo::Type as foo_alias1;
pub use self::foo_alias1 as foo_alias2;
pub use self::foo_alias2 as foo_alias3;
pub use self::anon_enum::Type as anon_enum_alias1;
pub use self::anon_enum_alias1 as anon_enum_alias2;
pub use self::anon_enum_alias2 as anon_enum_alias3;
#[repr(C)]
#[derive(Debug, Copy)]
pub struct bar {
Expand All @@ -36,10 +45,14 @@ pub struct bar {
pub member4: foo_alias3,
pub member5: ns1_foo::Type,
pub member6: *mut ns2_Foo::Type,
pub member7: anon_enum::Type,
pub member8: anon_enum_alias1,
pub member9: anon_enum_alias2,
pub member10: anon_enum_alias3,
}
#[test]
fn bindgen_test_layout_bar() {
assert_eq!(::std::mem::size_of::<bar>() , 32usize , concat ! (
assert_eq!(::std::mem::size_of::<bar>() , 48usize , concat ! (
"Size of: " , stringify ! ( bar ) ));
assert_eq! (::std::mem::align_of::<bar>() , 8usize , concat ! (
"Alignment of " , stringify ! ( bar ) ));
Expand Down Expand Up @@ -73,6 +86,26 @@ fn bindgen_test_layout_bar() {
, 24usize , concat ! (
"Alignment of field: " , stringify ! ( bar ) , "::" ,
stringify ! ( member6 ) ));
assert_eq! (unsafe {
& ( * ( 0 as * const bar ) ) . member7 as * const _ as usize }
, 32usize , concat ! (
"Alignment of field: " , stringify ! ( bar ) , "::" ,
stringify ! ( member7 ) ));
assert_eq! (unsafe {
& ( * ( 0 as * const bar ) ) . member8 as * const _ as usize }
, 36usize , concat ! (
"Alignment of field: " , stringify ! ( bar ) , "::" ,
stringify ! ( member8 ) ));
assert_eq! (unsafe {
& ( * ( 0 as * const bar ) ) . member9 as * const _ as usize }
, 40usize , concat ! (
"Alignment of field: " , stringify ! ( bar ) , "::" ,
stringify ! ( member9 ) ));
assert_eq! (unsafe {
& ( * ( 0 as * const bar ) ) . member10 as * const _ as usize
} , 44usize , concat ! (
"Alignment of field: " , stringify ! ( bar ) , "::" ,
stringify ! ( member10 ) ));
}
impl Clone for bar {
fn clone(&self) -> Self { *self }
Expand Down
14 changes: 14 additions & 0 deletions tests/headers/constify-module-enums-types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ typedef enum foo {
AND_ALSO_THIS = 42,
} foo;


typedef enum {
Variant1, Variant2, Variant3,
} anon_enum;


namespace ns1 {
typedef enum {
THIS,
Expand All @@ -28,13 +34,21 @@ typedef foo foo_alias1;
typedef foo_alias1 foo_alias2;
typedef foo_alias2 foo_alias3;

typedef anon_enum anon_enum_alias1;
typedef anon_enum_alias1 anon_enum_alias2;
typedef anon_enum_alias2 anon_enum_alias3;

typedef struct bar {
foo member1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add the new option to ns1::foo2, and add an usage of it here, I'm pretty sure it'd be broken.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the test; the behavior seems to be correct

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not with namespaces disabled. The following test still fails:

// bindgen-flags: --constified-enum-module one_Foo

namespace one {
  enum class Foo {
    Variant1, Variant2,
  };
}

class Bar {
  one::Foo* baz;
};

foo_alias1 member2;
foo_alias2 member3;
foo_alias3 member4;
ns1::foo member5;
ns2::Foo *member6;
anon_enum member7;
anon_enum_alias1 member8;
anon_enum_alias2 member9;
anon_enum_alias3 member10;
} bar;

class Baz {
Expand Down