rust-lang / rust-lang/rust-bindgen

bindgen generates conflicting definitions when template dependent parameters are used

Open
#3,160 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
5.3k
Forks
829
Avg merge
1d 1h
Merged PRs (30d)
15

Description

Reproduction:

Input C++:

namespace a {
typedef int b;
//inline namespace c {}
template <typename> class aa;
inline namespace c {
template <typename d, typename = d, typename = aa<d>> class e;
}
typedef e<char> f;
template <typename g, typename, template <typename> typename> struct h {
    using i = g;
};
template <typename g, template <typename> class k> using j = h<g, void, k>;
template <typename g, template <typename> class k>
using m = typename j<g, k>::i;
template <typename> struct l { typedef b ab; };
template <typename p> class aa {
public:
    typedef p n;
};
struct r {
    template <typename p> using o = typename p::c;
};
template <typename ad> struct u : r {
    typedef typename ad::n n;
    using ae = m<n, o>;
    template <typename af, typename> struct v { using i = typename l<f>::ab; };
    using ab = typename v<ad, ae>::i;
};
} // namespace a
namespace q {
template <typename ad> struct w : a::u<ad> {};
} // namespace q
namespace a {
inline namespace c {
template <typename, typename, typename ad> class e {
    typedef q::w<ad> s;
public:
    typedef typename s::ab ab;
};
} // namespace c
} // namespace a
namespace ag {
namespace ah {
typedef a::f::ab t;
class ai {
public:
    t aj;
};
class al;
namespace am {
class an {
public:
    void ao(ai);
};
} // namespace am
class ap {
public:
    al aq();
};
class ar {
public:
    am::an as;
};
class al {
public:
    ar at;
};
struct au {
    ap av;
};
} // namespace ah
} // namespace ag
namespace operations_research {
class aw {
public:
    ag::ah::au ax;
};
class Solver {
public:
    aw ay;
};
} // namespace operations_research

Command line:
cargo run -- test.hpp --no-layout-tests --enable-cxx-namespaces --allowlist-type operations_research::Solver -- -std=c++14

Resulting Rust:

/* automatically generated by rust-bindgen 0.71.1 */

#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
pub mod root {
    #[allow(unused_imports)]
    use self::super::root;
    pub mod a {
        #[allow(unused_imports)]
        use self::super::super::root;
        pub type b = ::std::os::raw::c_int;
    }
    pub mod ag {
        #[allow(unused_imports)]
        use self::super::super::root;
        pub mod ah {
            #[allow(unused_imports)]
            use self::super::super::super::root;
            pub type t = root::ab;
            #[repr(C)]
            #[derive(Debug, Copy, Clone)]
            pub struct ai {
                pub aj: root::ag::ah::t,
            }
            pub mod am {
                #[allow(unused_imports)]
                use self::super::super::super::super::root;
                #[repr(C)]
                #[derive(Debug, Copy, Clone)]
                pub struct an {
                    pub _address: u8,
                }
                unsafe extern "C" {
                    #[link_name = "\u{1}__ZN2ag2ah2am2an2aoENS0_2aiE"]
                    pub fn an_ao(
                        this: *mut root::ag::ah::am::an,
                        arg1: root::ag::ah::ai,
                    );
                }
                impl an {
                    #[inline]
                    pub unsafe fn ao(&mut self, arg1: root::ag::ah::ai) {
                        an_ao(self, arg1)
                    }
                }
            }
            #[repr(C)]
            #[derive(Debug, Copy, Clone)]
            pub struct ap {
                pub _address: u8,
            }
            unsafe extern "C" {
                #[link_name = "\u{1}__ZN2ag2ah2ap2aqEv"]
                pub fn ap_aq(this: *mut root::ag::ah::ap) -> root::ag::ah::al;
            }
            impl ap {
                #[inline]
                pub unsafe fn aq(&mut self) -> root::ag::ah::al {
                    ap_aq(self)
                }
            }
            #[repr(C)]
            #[derive(Debug, Copy, Clone)]
            pub struct ar {
                pub as_: root::ag::ah::am::an,
            }
            #[repr(C)]
            #[derive(Debug, Copy, Clone)]
            pub struct al {
                pub at: root::ag::ah::ar,
            }
            #[repr(C)]
            #[derive(Debug, Copy, Clone)]
            pub struct au {
                pub av: root::ag::ah::ap,
            }
        }
    }
    pub mod operations_research {
        #[allow(unused_imports)]
        use self::super::super::root;
        #[repr(C)]
        #[derive(Debug, Copy, Clone)]
        pub struct aw {
            pub ax: root::ag::ah::au,
        }
        #[repr(C)]
        #[derive(Debug, Copy, Clone)]
        pub struct Solver {
            pub ay: root::operations_research::aw,
        }
    }
    pub type ab = root::a::b;
    pub type ab = root::ab;
    pub type ab = root::i;
    pub type i = root::ab;
}

Note that near the end there are three defintions of ab, so the resulting Rust doesn't build.

Bindgen version 20aa65a0b9edfd5f8ab3e038197da5cb2c52ff18 (today's HEAD).

As you can see this code was already minimized a while ago for https://github.com/google/autocxx/issues/264, though that was a separate issue so it's quite possible it can be reduced more to get a more minimal test case for bindgen.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the cargo command in the issue against the provided test.hpp and inspect the generated Rust near the duplicate ab definitions. Trace how the C++ template-dependent types are represented in the output; done means the reproduced binding no longer contains conflicting definitions and builds successfully.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, rust
Domain
compilers, devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.