rust-lang / rust-lang/rust-bindgen
bindgen generates conflicting definitions when template dependent parameters are used
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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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