Apple LLVM 16 has headers with unused template parameters in strings
I can't build HEAD 48c74b6530db3dddda7fe8c20971ed664379b041 on one of my Macs, for unknown reasons. I get:
impl Goat {
///autocxx bindings couldn't be generated: Found an attempt at using a forward declaration (std::__1::string) inside a templated cxx type such as UniquePtr or CxxVector. If the forward declaration is a typedef, perhaps autocxx wasn't sure whether or not it involved a forward declaration. If you're sure it didn't, then you may be able to solve this by using instantiable!.
fn describe(_uhoh: autocxx::BindingGenerationFailure) {}
Note to self: a repro file is at ~/Downloads/repro-1396.json.zip
升级Xcode后,默认clang --version变成了 Apple clang version 16.0.0 (clang-1600.0.26.3), 再安装一下 15版本就可以了
brew install llvm@15
添加环境 ~/.zshrc
export PATH="/usr/local/opt/llvm@15/bin:$PATH" # Intel Mac
export PATH="/opt/homebrew/opt/llvm@15/bin:$PATH" # Apple Silicon
刷新环境
source ~/.zshrc
Thank you! Yes - however I need to make it ideally work with Apple's LLVM 16 headers. Somehow :)
A bit of diagnosis. TL;DR: this is going to be hard to fix, but if I can pull it off it might make autocxx work in quite a few more circumstances.
Diagnosis
autocxx-bindgen is giving us this for std::basic_string:
#[repr(C)]
#[cpp_semantics(unused_template_param)]
#[cpp_semantics(source_location(
"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/string",
709,
7,
42586
))]
pub struct basic_string {
__r_: root::std::__1::__compressed_pair,
}
The cpp_semantics attributes are the bits added by autocxx_bindgen on top of the standard bindgen output.
This is generated from C++ thus:
template <class _CharT, class _Traits, class _Allocator>
class basic_string {
// ...
}
The problem here is #[cpp_semantics(unused_template_param)].
bindgen does an analysis of which of a type's template parameters are used, by following edges on the graph from the type to each of its fields. Rust requires template arguments to be used, so when generating a templated type A<B,C,D> bindgen will generate A<B> if only B is required by its fields. (This is drastically simplifying the complexity of course).
That's fine for normal users of bindgen, but for us, we need to generate C++ code containing this type. Providing just A<B> may not work in C++ code.
So, in autocxx, we refuse to generate A<B> (or in this real case, std::basic_string) because we think it's always necessary to generate A<B,C,D> or std::basic_string<_CharT,_Traits,_Allocator>.
Hence we are currently completely refusing to generate std::basic_string, and all sorts of things fail.
I don't know what specifically changed with this version of Apple's string headers to cause this to occur now.
Solution option 1
- Instead of just generating
#[cpp_semantics(unused_template_param)],autocxx-bindgentells us which template parameters are unused. - We then always provide such parameters when specifying the type in C++, but they remain omitted from Rust.
Solution option 2
- Instead of just generating
#[cpp_semantics(unused_template_param)],autocxx-bindgentells us which template parameters are unused. - We then always provide such parameters when specifying the type in C++
- If we need to specify them in Rust for some reason (?) then we add a
PhantomData<B>field. I can't see any reason why this would occur, but we'll see
Solution option 3
- Instead of just generating
#[cpp_semantics(unused_template_param)],autocxx-bindgentells us which template parameters are unused. - We generate a
typedef A_concrete<B> A<B,C,D>along the lines of theinstantiate!directive. It's not clear what we'd put intoCorDhere but perhaps there's template magic to look up their default values, or something.
If I can get any of these to work, it should greatly increase autocxx's versatility to work with a wider range of templated types.
Hm, in fact - although there's a core of an idea there which might help autocxx in general - I don't think it solves everything (or even anything?) in this case. bindgen gives us this:
#[link_name = "\u{1}__Z11give_str_upv"]
pub fn give_str_up() -> root::std::__1::unique_ptr;
for the test_give_string_up test. So the returned type isn't complete enough, irrespective of any attributes autocxx adds.
Fixed by https://github.com/rust-lang/rust-bindgen/commit/7fd78ad70c0c4329206421109dc5259b7b923f7e which I've now rolled into autocxx-bindgen.