diff --git a/rs_bindings_from_cc/generate_bindings/lifetime_defaults_transform.rs b/rs_bindings_from_cc/generate_bindings/lifetime_defaults_transform.rs index 6bb731edf..be8d958b9 100644 --- a/rs_bindings_from_cc/generate_bindings/lifetime_defaults_transform.rs +++ b/rs_bindings_from_cc/generate_bindings/lifetime_defaults_transform.rs @@ -94,6 +94,7 @@ impl BindingContext { pub fn new() -> Self { let mut ctx = BindingContext { bindings: HashMap::new(), names: HashSet::new() }; ctx.push_new_binding(&Rc::from("static")); + ctx.push_new_binding(&Rc::from("unknown")); ctx } } @@ -154,9 +155,16 @@ impl<'a> LifetimeDefaults<'a> { ) -> LifetimeState { match lifetime { [] => LifetimeState::Unseen, - [id] => LifetimeState::Single( - self.bindings.get_or_push_new_binding(id, |name| new_bindings.push(name.clone())), - ), + [id] => { + let binding = self + .bindings + .get_or_push_new_binding(id, |name| new_bindings.push(name.clone())); + if binding.as_ref() == "unknown" { + LifetimeState::Unknown + } else { + LifetimeState::Single(binding) + } + } // TODO(b/454627672): multiple variables. _ => LifetimeState::Unknown, } diff --git a/rs_bindings_from_cc/generate_bindings/lifetime_defaults_transform_test.rs b/rs_bindings_from_cc/generate_bindings/lifetime_defaults_transform_test.rs index 51ee7c3a7..9546b0978 100644 --- a/rs_bindings_from_cc/generate_bindings/lifetime_defaults_transform_test.rs +++ b/rs_bindings_from_cc/generate_bindings/lifetime_defaults_transform_test.rs @@ -175,6 +175,37 @@ fn test_unique_lifetime_returned_for_single_ref() -> Result<()> { Ok(()) } +#[gtest] +fn test_unknown_lifetime_inhibits_default_lifetimes() -> Result<()> { + let ir = ir_from_assumed_lifetimes_cc( + &(with_full_lifetime_macros() + + r#" + int& f(int& $unknown i1); + "#), + )?; + let dir = lifetime_defaults_transform(&ir)?; + assert_ir_matches!( + dir, + quote! { + Func { + cc_name: "f", + rs_name: "f", ... + return_type: CcType { ... explicit_lifetimes: [] ... }, ... + params: [ + FuncParam { + type_: CcType { ... explicit_lifetimes: [] ... }, + identifier: "i1", ... + } + ], + ... + lifetime_inputs: [], + ... + } + } + ); + Ok(()) +} + #[gtest] fn test_no_lifetime_returned_for_distinct_ref_parameters() -> Result<()> { let ir = ir_from_assumed_lifetimes_cc( @@ -775,7 +806,7 @@ fn test_param_lifetimebound_to_this_in_constructor_explicit_lifetime() -> Result } #[gtest] -fn test_binding_context_has_static() -> Result<()> { +fn test_binding_context_has_builtin_lifetimes() -> Result<()> { let mut ctx = BindingContext::new(); let mut called = false; assert_eq!( @@ -783,6 +814,11 @@ fn test_binding_context_has_static() -> Result<()> { "static".into() ); assert!(!called); + assert_eq!( + ctx.get_or_push_new_binding(&Rc::from("unknown"), |_| called = true), + "unknown".into() + ); + assert!(!called); Ok(()) } @@ -871,6 +907,44 @@ fn test_struct_binds_lifetime_param() -> Result<()> { Ok(()) } +#[gtest] +fn test_struct_shadows_unknown_lifetime_param() -> Result<()> { + let ir = ir_from_assumed_lifetimes_cc( + &(with_full_lifetime_macros() + + r#" + struct LIFETIME_PARAMS("unknown") S { int& $unknown f(); }; + "#), + )?; + let dir = lifetime_defaults_transform(&ir)?; + assert_ir_matches!( + dir, + quote! { + Record { + ... + cc_name: "S", + ... + lifetime_inputs: ["unknown_0"], + ... + } + } + ); + assert_ir_matches!( + dir, + quote! { + Func { + cc_name: "f", + rs_name: "f", ... + return_type: CcType { ... explicit_lifetimes: ["unknown_0"] ... }, ... + lifetime_params: [], + ... + lifetime_inputs: [], + ... + } + } + ); + Ok(()) +} + #[gtest] fn test_struct_does_not_shadow_unrelated_lifetime_param() -> Result<()> { let ir = ir_from_assumed_lifetimes_cc( diff --git a/rs_bindings_from_cc/ir_testing.rs b/rs_bindings_from_cc/ir_testing.rs index bf36c3c0f..97bc43004 100644 --- a/rs_bindings_from_cc/ir_testing.rs +++ b/rs_bindings_from_cc/ir_testing.rs @@ -53,6 +53,7 @@ pub fn with_full_lifetime_macros() -> String { result.push_str(&format!("#define ${} $({})\n", l, l)); } result.push_str("#define $static $(static)\n"); + result.push_str("#define $unknown $(unknown)\n"); result }