Account for unstable mangling via regex-based checks in tests.
PiperOrigin-RevId: 494752346
diff --git a/cc_bindings_from_rs/BUILD b/cc_bindings_from_rs/BUILD
index 9a59171..5785497 100644
--- a/cc_bindings_from_rs/BUILD
+++ b/cc_bindings_from_rs/BUILD
@@ -74,6 +74,7 @@
],
deps = [
"//common:token_stream_matchers",
+ "@crate_index//:regex",
"@crate_index//:tempfile",
"@rules_rust//tools/runfiles",
],
diff --git a/cc_bindings_from_rs/bindings.rs b/cc_bindings_from_rs/bindings.rs
index 3f958ce..383fc6c 100644
--- a/cc_bindings_from_rs/bindings.rs
+++ b/cc_bindings_from_rs/bindings.rs
@@ -1825,6 +1825,9 @@
pub fn add(x: f64, y: f64) -> f64 { x * y }
"#;
test_format_def(test_src, "add", |result| {
+ // TODO(b/261074843): Re-add thunk name verification once we are using stable name
+ // mangling (which may be coming in Q1 2023). (This might mean reverting cl/492333432
+ // + manual review and tweaks.)
let result = result.expect("Test expects success here");
assert!(result.cc.prereqs.is_empty());
assert_cc_matches!(
@@ -3000,7 +3003,6 @@
{
use rustc_session::config::{
CodegenOptions, CrateType, Input, Options, OutputType, OutputTypes,
- SymbolManglingVersion,
};
const TEST_FILENAME: &str = "crubit_unittests.rs";
@@ -3025,14 +3027,6 @@
// As pointed out in `panics_and_exceptions.md` the tool only supports `-C
// panic=abort` and therefore we explicitly opt into this config for tests.
panic: Some(rustc_target::spec::PanicStrategy::Abort),
- // To simplify how unit tests are authored we force a specific mangling algorithm -
- // this way the tests can hardcode mangled-name-depdendent expectations (e.g. names
- // of thunks expected in test output). The value below has been chosen based on
- // <internal link>/llvm-coverage-instrumentation.html#rust-symbol-mangling which
- // points out that `v0` mangling can be used to "ensure consistent and reversible
- // name mangling" in situations when "mangled names must be consistent across
- // compilations".
- symbol_mangling_version: Some(SymbolManglingVersion::V0),
..Default::default()
},
..Default::default()
diff --git a/cc_bindings_from_rs/cc_bindings_from_rs.rs b/cc_bindings_from_rs/cc_bindings_from_rs.rs
index ee60f3d..e837724 100644
--- a/cc_bindings_from_rs/cc_bindings_from_rs.rs
+++ b/cc_bindings_from_rs/cc_bindings_from_rs.rs
@@ -221,6 +221,7 @@
use crate::bindings::tests::get_sysroot_for_testing;
use itertools::Itertools;
+ use regex::{Regex, RegexBuilder};
use std::path::PathBuf;
use tempfile::{tempdir, TempDir};
use token_stream_printer::RUSTFMT_EXE_PATH_FOR_TESTING;
@@ -329,9 +330,6 @@
args.extend([
"--".to_string(),
format!("--codegen=panic={}", &self.panic_mechanism),
- // See comments about `SymbolManglingVersion::V0`in `test::run_compiler` in
- // `bindings.rs` for rationale behind using `symbol-mangling-version=v0`.
- "--codegen=symbol-mangling-version=v0".to_string(),
"--crate-type=lib".to_string(),
format!("--sysroot={}", get_sysroot_for_testing().display()),
rs_input_path.display().to_string(),
@@ -344,6 +342,51 @@
}
}
+ // TODO(b/261074843): Go back to exact string matching (and hardcoding thunk
+ // names) once we are using stable name mangling (which may be coming in Q1
+ // 2023). ("Go back" = more or less revert cl/492292910 + manual review and
+ // tweaks.)
+ fn assert_body_matches(actual: &str, expected: &str) {
+ fn build_regex(expected_body: &str) -> Regex {
+ let patt = regex::escape(expected_body);
+ let patt = format!("^{patt}"); // Not always matching $ enables prefix checks below.
+ let patt = patt.replace("ANY_IDENTIFIER_CHARACTERS", "[a-zA-Z0-9_]*");
+ RegexBuilder::new(&patt).multi_line(false).dot_matches_new_line(false).build().unwrap()
+ }
+ let is_whole_h_body_matching = {
+ match build_regex(expected).shortest_match(&actual) {
+ None => false,
+ Some(len) => len == actual.len(),
+ }
+ };
+ if !is_whole_h_body_matching {
+ let longest_matching_expectation_len = (0..=expected.len())
+ .rev() // Iterating from longest to shortest prefix
+ .filter(|&len| {
+ expected
+ .get(0..len) // Only valid UTF-8 boundaries
+ .filter(|prefix| build_regex(prefix).is_match(&actual))
+ .is_some()
+ })
+ .next() // Getting the first regex that matched
+ .unwrap(); // We must get a match at least for 0-length expected body
+ let longest_matching_regex =
+ build_regex(&expected[0..longest_matching_expectation_len]);
+ let len_of_longest_match = longest_matching_regex.shortest_match(&actual).unwrap(); // Again - we must get a match at least for 0-length expected body
+ let mut marked_body = actual.to_string();
+ marked_body.insert_str(len_of_longest_match, "!!!>>>");
+ let mut marked_pattern = expected.to_string();
+ marked_pattern.insert_str(longest_matching_expectation_len, "!!!>>>");
+ panic!(
+ "h_body didn't match expectations:\n\
+ #### Actual body (first mismatch follows the \"!!!>>>\" marker):\n\
+ {marked_body}\n\
+ #### Mismatched pattern (mismatch follows the \"!!!>>>\" marker):\n\
+ {marked_pattern}"
+ );
+ }
+ }
+
#[test]
fn test_happy_path() -> anyhow::Result<()> {
let test_args = TestArgs::default_args()?;
@@ -351,38 +394,39 @@
assert!(test_result.h_path.exists());
let h_body = std::fs::read_to_string(&test_result.h_path)?;
- assert_eq!(
- h_body,
-r#"// Automatically @generated C++ bindings for the following Rust crate:
+ assert_body_matches(
+ &h_body,
+ r#"// Automatically @generated C++ bindings for the following Rust crate:
// test_crate
#pragma once
namespace test_crate {
namespace __crubit_internal {
-extern "C" void __crubit_thunk__RNvCsqz8GFuO9cP_10test_crate15public_function();
+extern "C" void
+__crubit_thunk__ANY_IDENTIFIER_CHARACTERS();
}
inline void public_function() {
return __crubit_internal::
- __crubit_thunk__RNvCsqz8GFuO9cP_10test_crate15public_function();
+ __crubit_thunk__ANY_IDENTIFIER_CHARACTERS();
}
-} // namespace test_crate"#
+} // namespace test_crate"#,
);
assert!(test_result.rs_path.exists());
let rs_body = std::fs::read_to_string(&test_result.rs_path)?;
- assert_eq!(
- rs_body,
+ assert_body_matches(
+ &rs_body,
r#"// Automatically @generated C++ bindings for the following Rust crate:
// test_crate
#![allow(improper_ctypes_definitions)]
#[no_mangle]
-extern "C" fn __crubit_thunk__RNvCsqz8GFuO9cP_10test_crate15public_function() -> () {
+extern "C" fn __crubit_thunk__ANY_IDENTIFIER_CHARACTERS() -> () {
::test_crate::public_function()
}
-"#
+"#,
);
Ok(())
}