diff --git a/syntax/mangle.rs b/syntax/mangle.rs index 1b10fb7e7..418a6e776 100644 --- a/syntax/mangle.rs +++ b/syntax/mangle.rs @@ -7,6 +7,7 @@ // defining characteristics: // - 2 segments // - starts with cxxbridge +// TODO: should these also include {CXXVERSION}? // // (b) Behavior on a builtin binding without generic parameter. // pattern: {CXXBRIDGE} $ {TYPE} $ {NAME} @@ -15,6 +16,7 @@ // defining characteristics: // - 3 segments // - starts with cxxbridge +// TODO: should these also include {CXXVERSION}? // // (c) Behavior on a builtin binding with generic parameter. // pattern: {CXXBRIDGE} $ {TYPE} $ {PARAM...} $ {NAME} @@ -24,33 +26,35 @@ // defining characteristics: // - 4+ segments // - starts with cxxbridge +// TODO: should these also include {CXXVERSION}? (always? or only for +// ones implicitly or explicitly `impl`-ed by the user?) // // (d) User-defined extern function. -// pattern: {NAMESPACE...} $ {CXXBRIDGE} $ {NAME} +// pattern: {NAMESPACE...} $ {CXXBRIDGE} $ {CXXVERSION} $ {NAME} // examples: -// - cxxbridge1$new_client -// - org$rust$cxxbridge1$new_client +// - cxxbridge1$v187$new_client +// - org$rust$cxxbridge1$v187$new_client // defining characteristics: -// - cxxbridge is second from end +// - cxxbridge is third from end // FIXME: conflict with (a) if they collide with one of our one-off symbol names in the global namespace // // (e) User-defined extern member function. -// pattern: {NAMESPACE...} $ {CXXBRIDGE} $ {TYPE} $ {NAME} +// pattern: {NAMESPACE...} $ {CXXBRIDGE} $ {CXXVERSION} $ {TYPE} $ {NAME} // examples: -// - org$cxxbridge1$Struct$get +// - org$cxxbridge1$v187$Struct$get // defining characteristics: -// - cxxbridge is third from end +// - cxxbridge is fourth from end // FIXME: conflict with (b) if e.g. user binds a type in global namespace that collides with our builtin type names // // (f) Operator overload. -// pattern: {NAMESPACE...} $ {CXXBRIDGE} $ {TYPE} $ operator $ {NAME} +// pattern: {NAMESPACE...} $ {CXXBRIDGE} $ {CXXVERSION} $ {TYPE} $ operator $ {NAME} // examples: -// - org$rust$cxxbridge1$Struct$operator$eq +// - org$rust$cxxbridge1$v187$Struct$operator$eq // defining characteristics: // - second segment from end is `operator` (not possible in type or namespace names) // // (g) Closure trampoline. -// pattern: {NAMESPACE...} $ {CXXBRIDGE} $ {TYPE?} $ {NAME} $ {ARGUMENT} $ {DIRECTION} +// pattern: {NAMESPACE...} $ {CXXBRIDGE} $ {CXXVERSION} $ {TYPE?} $ {NAME} $ {ARGUMENT} $ {DIRECTION} // examples: // - org$rust$cxxbridge1$Struct$invoke$f$0 // defining characteristics: @@ -78,6 +82,11 @@ use crate::syntax::{ExternFn, Pair, Types}; const CXXBRIDGE: &str = "cxxbridge1"; +// Ignoring `CARGO_PKG_VERSION_MAJOR` and `...MINOR`, because they don't agree across +// all the crates. For example `gen/lib/Cargo.toml` says `version = "0.7.xxx"`, but +// `macro/Cargo.toml` says `version = "1.0.xxx"`. +const CXXVERSION: &str = concat!("v", env!("CARGO_PKG_VERSION_PATCH")); + macro_rules! join { ($($segment:expr),+ $(,)?) => { symbol::join(&[$(&$segment),+]) @@ -91,11 +100,12 @@ pub(crate) fn extern_fn(efn: &ExternFn, types: &Types) -> Symbol { join!( efn.name.namespace, CXXBRIDGE, + CXXVERSION, self_type_ident.name.cxx, efn.name.rust, ) } - None => join!(efn.name.namespace, CXXBRIDGE, efn.name.rust), + None => join!(efn.name.namespace, CXXBRIDGE, CXXVERSION, efn.name.rust), } } @@ -103,6 +113,7 @@ pub(crate) fn operator(receiver: &Pair, operator: &'static str) -> Symbol { join!( receiver.namespace, CXXBRIDGE, + CXXVERSION, receiver.cxx, "operator", operator, diff --git a/tests/cxx_gen.rs b/tests/cxx_gen.rs index 93e25307e..d476caa45 100644 --- a/tests/cxx_gen.rs +++ b/tests/cxx_gen.rs @@ -18,7 +18,7 @@ fn test_extern_c_function() { let output = str::from_utf8(&generated.implementation).unwrap(); // To avoid continual breakage we won't test every byte. // Let's look for the major features. - assert!(output.contains("void cxxbridge1$do_cpp_thing(::rust::Str foo)")); + assert!(output.contains(&format!("void {CXXPREFIX}$do_cpp_thing(::rust::Str foo)"))); } #[test] @@ -28,9 +28,13 @@ fn test_impl_annotation() { let source = BRIDGE0.parse().unwrap(); let generated = generate_header_and_cc(source, &opt).unwrap(); let output = str::from_utf8(&generated.implementation).unwrap(); - assert!(output.contains("ANNOTATION void cxxbridge1$do_cpp_thing(::rust::Str foo)")); + assert!(output.contains(&format!( + "ANNOTATION void {CXXPREFIX}$do_cpp_thing(::rust::Str foo)" + ))); } +const CXXPREFIX: &'static str = concat!("cxxbridge1$v", env!("CARGO_PKG_VERSION_PATCH")); + const BRIDGE1: &str = r#" #[cxx::bridge] mod ffi { @@ -66,10 +70,13 @@ fn test_extern_rust_method_on_c_type() { assert!(!header.contains("rust_method_cpp_receiver")); // Check that there is a generated C signature bridging to the Rust method. - assert!(implementation - .contains("void cxxbridge1$CppType$rust_method_cpp_receiver(::CppType &self) noexcept;")); + assert!(implementation.contains(&format!( + "void {CXXPREFIX}$CppType$rust_method_cpp_receiver(::CppType &self) noexcept;" + ))); // Check that there is an implementation on the C++ class calling the Rust method. assert!(implementation.contains("void CppType::rust_method_cpp_receiver() noexcept {")); - assert!(implementation.contains("cxxbridge1$CppType$rust_method_cpp_receiver(*this);")); + assert!(implementation.contains(&format!( + "{CXXPREFIX}$CppType$rust_method_cpp_receiver(*this);" + ))); }