diff --git a/src/bindgen/ir/generic_path.rs b/src/bindgen/ir/generic_path.rs index 9a89d04..8db3d3f 100644 --- a/src/bindgen/ir/generic_path.rs +++ b/src/bindgen/ir/generic_path.rs @@ -27,6 +27,32 @@ impl GenericParams { .collect(), ) } + + fn write_internal( + &self, + config: &Config, + out: &mut SourceWriter, + with_default: bool, + ) { + if !self.0.is_empty() && config.language == Language::Cxx { + out.write("template<"); + for (i, item) in self.0.iter().enumerate() { + if i != 0 { + out.write(", "); + } + write!(out, "typename {}", item); + if with_default { + write!(out, " = void"); + } + } + out.write(">"); + out.new_line(); + } + } + + pub fn write_with_default(&self, config: &Config, out: &mut SourceWriter) { + self.write_internal(config, out, true); + } } impl Deref for GenericParams { @@ -39,17 +65,7 @@ impl Deref for GenericParams { impl Source for GenericParams { fn write(&self, config: &Config, out: &mut SourceWriter) { - if !self.0.is_empty() && config.language == Language::Cxx { - out.write("template<"); - for (i, item) in self.0.iter().enumerate() { - if i != 0 { - out.write(", "); - } - write!(out, "typename {}", item); - } - out.write(">"); - out.new_line(); - } + self.write_internal(config, out, false); } } diff --git a/src/bindgen/ir/opaque.rs b/src/bindgen/ir/opaque.rs index a46dcee..2efd397 100644 --- a/src/bindgen/ir/opaque.rs +++ b/src/bindgen/ir/opaque.rs @@ -105,12 +105,16 @@ impl Item for OpaqueItem { out: &mut Monomorphs, ) { assert!( - self.generic_params.len() > 0, + !self.generic_params.is_empty(), "{} is not generic", self.path ); + + // We can be instantiated with less generic params because of default + // template parameters, or because of empty types that we remove during + // parsing (`()`). assert!( - self.generic_params.len() == generic_values.len(), + self.generic_params.len() >= generic_values.len(), "{} has {} params but is being instantiated with {} values", self.path, self.generic_params.len(), @@ -137,7 +141,7 @@ impl Source for OpaqueItem { self.documentation.write(config, out); - self.generic_params.write(config, out); + self.generic_params.write_with_default(config, out); if config.style.generate_typedef() && config.language == Language::C { write!( diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index 55280f2..831c37f 100644 --- a/src/bindgen/parser.rs +++ b/src/bindgen/parser.rs @@ -391,7 +391,7 @@ impl Parse { add_opaque("Option", vec!["T"]); add_opaque("NonNull", vec!["T"]); add_opaque("Vec", vec!["T"]); - add_opaque("HashMap", vec!["K", "V"]); + add_opaque("HashMap", vec!["K", "V", "Hasher"]); add_opaque("BTreeMap", vec!["K", "V"]); add_opaque("HashSet", vec!["T"]); add_opaque("BTreeSet", vec!["T"]); diff --git a/tests/expectations/both/opaque.c b/tests/expectations/both/opaque.c new file mode 100644 index 0000000..75614b6 --- /dev/null +++ b/tests/expectations/both/opaque.c @@ -0,0 +1,28 @@ +#ifdef __cplusplus +// These could be added as opaque types I guess. +template +struct BuildHasherDefault; + +struct DefaultHasher; +#endif + + +#include +#include +#include +#include + +typedef struct HashMap_i32__i32__BuildHasherDefault_DefaultHasher HashMap_i32__i32__BuildHasherDefault_DefaultHasher; + +typedef struct Result_Foo Result_Foo; + +/** + * Fast hash map used internally. + */ +typedef HashMap_i32__i32__BuildHasherDefault_DefaultHasher FastHashMap_i32__i32; + +typedef FastHashMap_i32__i32 Foo; + +typedef Result_Foo Bar; + +void root(const Foo *a, const Bar *b); diff --git a/tests/expectations/both/opaque.compat.c b/tests/expectations/both/opaque.compat.c new file mode 100644 index 0000000..a467628 --- /dev/null +++ b/tests/expectations/both/opaque.compat.c @@ -0,0 +1,36 @@ +#ifdef __cplusplus +// These could be added as opaque types I guess. +template +struct BuildHasherDefault; + +struct DefaultHasher; +#endif + + +#include +#include +#include +#include + +typedef struct HashMap_i32__i32__BuildHasherDefault_DefaultHasher HashMap_i32__i32__BuildHasherDefault_DefaultHasher; + +typedef struct Result_Foo Result_Foo; + +/** + * Fast hash map used internally. + */ +typedef HashMap_i32__i32__BuildHasherDefault_DefaultHasher FastHashMap_i32__i32; + +typedef FastHashMap_i32__i32 Foo; + +typedef Result_Foo Bar; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root(const Foo *a, const Bar *b); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/cell.cpp b/tests/expectations/cell.cpp index 2c16e26..443fa6f 100644 --- a/tests/expectations/cell.cpp +++ b/tests/expectations/cell.cpp @@ -3,10 +3,10 @@ #include #include -template +template struct NotReprC; -template +template struct RefCell; using Foo = NotReprC>; diff --git a/tests/expectations/monomorph-1.cpp b/tests/expectations/monomorph-1.cpp index 7d56cc6..e4c94c0 100644 --- a/tests/expectations/monomorph-1.cpp +++ b/tests/expectations/monomorph-1.cpp @@ -3,7 +3,7 @@ #include #include -template +template struct Bar; template diff --git a/tests/expectations/monomorph-3.cpp b/tests/expectations/monomorph-3.cpp index 05dc8a6..e15c407 100644 --- a/tests/expectations/monomorph-3.cpp +++ b/tests/expectations/monomorph-3.cpp @@ -3,7 +3,7 @@ #include #include -template +template struct Bar; template diff --git a/tests/expectations/opaque.c b/tests/expectations/opaque.c new file mode 100644 index 0000000..75614b6 --- /dev/null +++ b/tests/expectations/opaque.c @@ -0,0 +1,28 @@ +#ifdef __cplusplus +// These could be added as opaque types I guess. +template +struct BuildHasherDefault; + +struct DefaultHasher; +#endif + + +#include +#include +#include +#include + +typedef struct HashMap_i32__i32__BuildHasherDefault_DefaultHasher HashMap_i32__i32__BuildHasherDefault_DefaultHasher; + +typedef struct Result_Foo Result_Foo; + +/** + * Fast hash map used internally. + */ +typedef HashMap_i32__i32__BuildHasherDefault_DefaultHasher FastHashMap_i32__i32; + +typedef FastHashMap_i32__i32 Foo; + +typedef Result_Foo Bar; + +void root(const Foo *a, const Bar *b); diff --git a/tests/expectations/opaque.compat.c b/tests/expectations/opaque.compat.c new file mode 100644 index 0000000..a467628 --- /dev/null +++ b/tests/expectations/opaque.compat.c @@ -0,0 +1,36 @@ +#ifdef __cplusplus +// These could be added as opaque types I guess. +template +struct BuildHasherDefault; + +struct DefaultHasher; +#endif + + +#include +#include +#include +#include + +typedef struct HashMap_i32__i32__BuildHasherDefault_DefaultHasher HashMap_i32__i32__BuildHasherDefault_DefaultHasher; + +typedef struct Result_Foo Result_Foo; + +/** + * Fast hash map used internally. + */ +typedef HashMap_i32__i32__BuildHasherDefault_DefaultHasher FastHashMap_i32__i32; + +typedef FastHashMap_i32__i32 Foo; + +typedef Result_Foo Bar; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root(const Foo *a, const Bar *b); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/opaque.cpp b/tests/expectations/opaque.cpp new file mode 100644 index 0000000..e604fe6 --- /dev/null +++ b/tests/expectations/opaque.cpp @@ -0,0 +1,33 @@ +#ifdef __cplusplus +// These could be added as opaque types I guess. +template +struct BuildHasherDefault; + +struct DefaultHasher; +#endif + + +#include +#include +#include +#include + +template +struct HashMap; + +template +struct Result; + +/// Fast hash map used internally. +template +using FastHashMap = HashMap>; + +using Foo = FastHashMap; + +using Bar = Result; + +extern "C" { + +void root(const Foo *a, const Bar *b); + +} // extern "C" diff --git a/tests/expectations/std_lib.cpp b/tests/expectations/std_lib.cpp index 261522e..c756dce 100644 --- a/tests/expectations/std_lib.cpp +++ b/tests/expectations/std_lib.cpp @@ -3,15 +3,15 @@ #include #include -template +template struct Option; -template +template struct Result; struct String; -template +template struct Vec; extern "C" { diff --git a/tests/expectations/swift_name.cpp b/tests/expectations/swift_name.cpp index 739ca6f..89d4442 100644 --- a/tests/expectations/swift_name.cpp +++ b/tests/expectations/swift_name.cpp @@ -5,7 +5,7 @@ #include #include -template +template struct Box; struct Opaque; diff --git a/tests/expectations/tag/opaque.c b/tests/expectations/tag/opaque.c new file mode 100644 index 0000000..5728f2e --- /dev/null +++ b/tests/expectations/tag/opaque.c @@ -0,0 +1,28 @@ +#ifdef __cplusplus +// These could be added as opaque types I guess. +template +struct BuildHasherDefault; + +struct DefaultHasher; +#endif + + +#include +#include +#include +#include + +struct HashMap_i32__i32__BuildHasherDefault_DefaultHasher; + +struct Result_Foo; + +/** + * Fast hash map used internally. + */ +typedef struct HashMap_i32__i32__BuildHasherDefault_DefaultHasher FastHashMap_i32__i32; + +typedef FastHashMap_i32__i32 Foo; + +typedef struct Result_Foo Bar; + +void root(const Foo *a, const Bar *b); diff --git a/tests/expectations/tag/opaque.compat.c b/tests/expectations/tag/opaque.compat.c new file mode 100644 index 0000000..ae56420 --- /dev/null +++ b/tests/expectations/tag/opaque.compat.c @@ -0,0 +1,36 @@ +#ifdef __cplusplus +// These could be added as opaque types I guess. +template +struct BuildHasherDefault; + +struct DefaultHasher; +#endif + + +#include +#include +#include +#include + +struct HashMap_i32__i32__BuildHasherDefault_DefaultHasher; + +struct Result_Foo; + +/** + * Fast hash map used internally. + */ +typedef struct HashMap_i32__i32__BuildHasherDefault_DefaultHasher FastHashMap_i32__i32; + +typedef FastHashMap_i32__i32 Foo; + +typedef struct Result_Foo Bar; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root(const Foo *a, const Bar *b); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/rust/opaque.rs b/tests/rust/opaque.rs new file mode 100644 index 0000000..7e1c6be --- /dev/null +++ b/tests/rust/opaque.rs @@ -0,0 +1,10 @@ +/// Fast hash map used internally. +type FastHashMap = + std::collections::HashMap>; + +pub type Foo = FastHashMap; + +pub type Bar = Result; + +#[no_mangle] +pub extern "C" fn root(a: &Foo, b: &Bar) {} diff --git a/tests/rust/opaque.toml b/tests/rust/opaque.toml new file mode 100644 index 0000000..d7219e1 --- /dev/null +++ b/tests/rust/opaque.toml @@ -0,0 +1,9 @@ +header = """ +#ifdef __cplusplus +// These could be added as opaque types I guess. +template +struct BuildHasherDefault; + +struct DefaultHasher; +#endif +"""