Skip to content

Commit 265593b

Browse files
committed
Fix name collision between C enum and typedef
1 parent 32b5b2c commit 265593b

File tree

4 files changed

+96
-6
lines changed

4 files changed

+96
-6
lines changed

bindgen-tests/tests/expectations/tests/enum-typedef.rs

Lines changed: 0 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bindgen/codegen/mod.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2733,6 +2733,7 @@ impl<'a> EnumBuilder<'a> {
27332733
repr: proc_macro2::TokenStream,
27342734
enum_variation: EnumVariation,
27352735
enum_codegen_depth: usize,
2736+
has_typedef: bool,
27362737
) -> Self {
27372738
let ident = Ident::new(name, Span::call_site());
27382739

@@ -2767,10 +2768,12 @@ impl<'a> EnumBuilder<'a> {
27672768
EnumVariation::Consts => {
27682769
let mut variants = Vec::new();
27692770

2770-
variants.push(quote! {
2771-
#( #attrs )*
2772-
pub type #ident = #repr;
2773-
});
2771+
if !has_typedef {
2772+
variants.push(quote! {
2773+
#( #attrs )*
2774+
pub type #ident = #repr;
2775+
});
2776+
}
27742777

27752778
EnumBuilder::Consts {
27762779
variants,
@@ -3193,13 +3196,15 @@ impl CodeGenerator for Enum {
31933196
}
31943197

31953198
let repr = repr.to_rust_ty_or_opaque(ctx, item);
3199+
let has_typedef = ctx.is_enum_typedef_combo(item.id());
31963200

31973201
let mut builder = EnumBuilder::new(
31983202
&name,
31993203
attrs,
32003204
repr,
32013205
variation,
32023206
item.codegen_depth(ctx),
3207+
has_typedef,
32033208
);
32043209

32053210
// A map where we keep a value -> variant relation.

bindgen/ir/context.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,22 @@ pub struct BindgenContext {
399399
/// bitfield allocation units computed. Drained in `compute_bitfield_units`.
400400
need_bitfield_allocation: Vec<ItemId>,
401401

402+
/// The set of enums that are defined by a pair of `enum` and `typedef`,
403+
/// which is legal in C (but not C++).
404+
///
405+
/// ```c++
406+
/// // in either order
407+
/// enum Enum { Variants... };
408+
/// typedef int16_t Enum;
409+
/// ```
410+
///
411+
/// The stored `ItemId` is that of the `TypeKind::Enum`, not of the
412+
/// `TypeKind::Alias`.
413+
///
414+
/// This is populated when we enter codegen by `compute_enum_typedef_combos`
415+
/// and is always `None` before that and `Some` after.
416+
enum_typedef_combos: Option<HashSet<ItemId>>,
417+
402418
/// The set of (`ItemId`s of) types that can't derive debug.
403419
///
404420
/// This is populated when we enter codegen by `compute_cannot_derive_debug`
@@ -566,6 +582,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
566582
codegen_items: None,
567583
used_template_parameters: None,
568584
need_bitfield_allocation: Default::default(),
585+
enum_typedef_combos: None,
569586
cannot_derive_debug: None,
570587
cannot_derive_default: None,
571588
cannot_derive_copy: None,
@@ -1163,6 +1180,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
11631180
self.compute_sizedness();
11641181
self.compute_has_destructor();
11651182
self.find_used_template_parameters();
1183+
self.compute_enum_typedef_combos();
11661184
self.compute_cannot_derive_debug();
11671185
self.compute_cannot_derive_default();
11681186
self.compute_cannot_derive_copy();
@@ -2477,6 +2495,70 @@ If you encounter an error missing from this list, please file an issue or a PR!"
24772495
self.generated_bindgen_complex.get()
24782496
}
24792497

2498+
/// Compute which `enum`s have an associated `typedef` definition.
2499+
fn compute_enum_typedef_combos(&mut self) {
2500+
let _t = self.timer("compute_enum_typedef_combos");
2501+
assert!(self.enum_typedef_combos.is_none());
2502+
2503+
let mut enum_typedef_combos = HashSet::default();
2504+
for item in &self.items {
2505+
if let Some(ItemKind::Module(module)) =
2506+
item.as_ref().map(Item::kind)
2507+
{
2508+
// Find typedefs in this module, and build set of their names.
2509+
let mut names_of_typedefs = HashSet::default();
2510+
for child_id in module.children() {
2511+
if let Some(ItemKind::Type(ty)) =
2512+
self.items[child_id.0].as_ref().map(Item::kind)
2513+
{
2514+
if let (Some(name), TypeKind::Alias(type_id)) =
2515+
(ty.name(), ty.kind())
2516+
{
2517+
// We disregard aliases that refer to the enum
2518+
// itself, such as in `typedef enum { ... } Enum;`.
2519+
if type_id
2520+
.into_resolver()
2521+
.through_type_refs()
2522+
.through_type_aliases()
2523+
.resolve(self)
2524+
.expect_type()
2525+
.is_int()
2526+
{
2527+
names_of_typedefs.insert(name);
2528+
}
2529+
}
2530+
}
2531+
}
2532+
2533+
// Find enums in this module, and record the id of each one that
2534+
// has a typedef.
2535+
for child_id in module.children() {
2536+
if let Some(ItemKind::Type(ty)) =
2537+
self.items[child_id.0].as_ref().map(Item::kind)
2538+
{
2539+
if let (Some(name), true) = (ty.name(), ty.is_enum()) {
2540+
if names_of_typedefs.contains(name) {
2541+
enum_typedef_combos.insert(*child_id);
2542+
}
2543+
}
2544+
}
2545+
}
2546+
}
2547+
}
2548+
2549+
self.enum_typedef_combos = Some(enum_typedef_combos);
2550+
}
2551+
2552+
/// Look up whether `id` refers to an `enum` whose underlying type is
2553+
/// defined by a `typedef`.
2554+
pub fn is_enum_typedef_combo(&self, id: ItemId) -> bool {
2555+
assert!(
2556+
self.in_codegen_phase(),
2557+
"We only compute enum_typedef_combos when we enter codegen",
2558+
);
2559+
self.enum_typedef_combos.as_ref().unwrap().contains(&id)
2560+
}
2561+
24802562
/// Compute whether we can derive debug.
24812563
fn compute_cannot_derive_debug(&mut self) {
24822564
let _t = self.timer("compute_cannot_derive_debug");

bindgen/ir/ty.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ impl Type {
9595
matches!(self.kind, TypeKind::BlockPointer(..))
9696
}
9797

98+
/// Is this an integer type, including `bool` or `char`?
99+
pub fn is_int(&self) -> bool {
100+
matches!(self.kind, TypeKind::Int(_))
101+
}
102+
98103
/// Is this a compound type?
99104
pub fn is_comp(&self) -> bool {
100105
matches!(self.kind, TypeKind::Comp(..))

0 commit comments

Comments
 (0)