Skip to content

Bindgen fails to parse math.h #2596

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

Closed
CGMossa opened this issue Aug 2, 2023 · 5 comments
Closed

Bindgen fails to parse math.h #2596

CGMossa opened this issue Aug 2, 2023 · 5 comments

Comments

@CGMossa
Copy link
Contributor

CGMossa commented Aug 2, 2023

Input C/C++ Header

#include <math.h>

Bindgen Invocation

$ bindgen test.h -o test.rs

Actual Results

error[E0428]: the name `FP_INT_UPWARD` is defined multiple times
   --> src/bindings/R_ext/Arith.rs:167:1
    |
151 | pub const FP_INT_UPWARD: u32 = 0;
    | --------------------------------- previous definition of the value `FP_INT_UPWARD` here
...
167 | pub const FP_INT_UPWARD: _bindgen_ty_1 = _bindgen_ty_1::FP_INT_UPWARD;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `FP_INT_UPWARD` redefined here
    |
    = note: `FP_INT_UPWARD` must be defined only once in the value namespace of this module

This was on wsl, ubuntu, jammy, and using Ubuntu clang version 14.0.0-1ubuntu1.1.
I tried with clang-15, same result.

The issue is that this gets generated in the same file:

pub type _bindgen_ty_1 = ::std::os::raw::c_uint;
pub const FP_INT_UPWARD: u32 = 0;
pub const FP_INT_UPWARD: _bindgen_ty_1 = 0;

Expected Results

If I run the same on my Windows installation, I don't get whatever is going on here. In fact, I don't get these
things at all.

clang version 16.0.6
@CGMossa
Copy link
Contributor Author

CGMossa commented Aug 3, 2023

This is a rediscovery of #687; A solution was proposed then that looks like this #687 (comment)
Is this what we can do here?

@CGMossa
Copy link
Contributor Author

CGMossa commented Aug 3, 2023

In that thread, someone else has made it known about the regression: #687 (comment)

@pvdrz
Copy link
Contributor

pvdrz commented Aug 8, 2023

I don't think there's a regression. The bindgen invocation you provided is not using any of the options that can fix this.

@CGMossa
Copy link
Contributor Author

CGMossa commented Aug 8, 2023

I did use the advice of the stuff I found, but isn't it supposed to work? If not, feel free to close this issue then.

@pvdrz
Copy link
Contributor

pvdrz commented Aug 8, 2023

I did use the advice of the stuff I found

then please include it in the issue description.

but isn't it supposed to work?

what's "it"? If you mean that this should work with the invocation you provided, then it is not supposed to work.

The underlying problem here is that C programmers tend to use nameless enums to define groups of constants as mentioned in the "regressed" issue. In math.h, this is the relevant section of code (at least on my system's headers):

enum
  {
    FP_INT_UPWARD =
# define FP_INT_UPWARD 0
      FP_INT_UPWARD,
    FP_INT_DOWNWARD =
# define FP_INT_DOWNWARD 1
      FP_INT_DOWNWARD,
    FP_INT_TOWARDZERO =
# define FP_INT_TOWARDZERO 2
      FP_INT_TOWARDZERO,
    FP_INT_TONEARESTFROMZERO =
# define FP_INT_TONEARESTFROMZERO 3
      FP_INT_TONEARESTFROMZERO,
    FP_INT_TONEAREST =
# define FP_INT_TONEAREST 4
      FP_INT_TONEAREST,
  };

As you can see, this defines a C enum without a name where each enumerator uses a macro to define a constant and immeadiately uses that constant. As C enums are treated as constants by bindgen, this causes a collision where FP_INT_UPWARD and the rest of the enumerators are defined twice: once in the macro and another time in the enumerator.

Given that people could also write this:

enum {
  BAR =
#define BAR 0
      BAR,
} Foo;

it is not immediately clear what to do with each definition as users might want to keep the macro-defined constant and:

  • Turn Foo into a Rust enum so they can do Foo::BAR
  • Turn Foo into a module so they can do foo::BAR
  • Add Foo as a prefix so they can do Foo_BAR

So in your particular case, this C enum doesn't have a name, which means that keeping both the macro and the enumerator is irrelevant and you can easily ignore it with the suggestion I linked above: you either use a ParseCallback to ignore all the FP_INT_.* macros, or use --blocklist-item="FP_INT_.*" to ignore the enumerators, the result should be the same

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants