Repository: google/autocxx (rust)

Issue:
Multiple definition error across multiple include_cpp calls
## Expected Behavior
This shouldn't crash and the symbols should be properly mangled so they don't conflict across `include_cpp` calls.

## Actual Behavior

```
error: linking with `cc` failed: exit status: 1
  |
  = note: command omitted for brevity
  = note: /usr/bin/ld: /autocxx-err/target/debug/build/autocxx-err-1cd1cc8230fa4802/out/libmultifileerror.a(172f5ed9fec53081-gen2.o): in function `cxxbridge1$new_autocxx_autocxx_wrapper':
          /autocxx-err/target/debug/build/autocxx-err-1cd1cc8230fa4802/out/autocxx-build-dir/cxx/gen2.cxx:136: multiple definition of `cxxbridge1$new_autocxx_autocxx_wrapper'; /autocxx-err/target/debug/build/autocxx-err-1cd1cc8230fa4802/out/libmultifileerror.a(172f5ed9fec53081-gen0.o):/autocxx-err/target/debug/build/autocxx-err-1cd1cc8230fa4802/out/autocxx-build-dir/cxx/gen0.cxx:136: first defined here
          collect2: error: ld returned 1 exit status
```

It should be noted that the name of the files (e.x. `gen2.cxx`, `gen0.cxx`) is consistent after running `cargo clean` and then recompiling.

## Steps to Reproduce the Problem

`src/thing.h`:
```cpp
#pragma once

struct Thing {
    float id;

    Thing(float id) : id(id) {}
};
```

`src/item.h`:
```cpp
#pragma once

struct Item {
    float id;

    Item(float id) : id(id) {}
};
```

`src/main.rs`:
```rust
use autocxx::WithinUniquePtr;

autocxx::include_cpp! {
    #include "thing.h"
    name!(thing)
    safety!(unsafe)
    generate!("Thing")
}

autocxx::include_cpp! {
    #include "item.h"
    name!(item)
    safety!(unsafe)
    generate!("Item")
}

fn main() {
    let thing = thing::Thing::new(15.).within_unique_ptr();
    let item = item::Item::new(15.).within_unique_ptr();
}
```

`src/build.rs`:
```rust
use autocxx_build::Builder;
use miette::Result;

fn main() -> Result<()> {
    Builder::new("src/main.rs", ["src/"])
        .build()?
        .warnings(false)
        .compile("multifileerror");

    println!("cargo:rerun-if-changed=src/lib.rs");

    Ok(())
}
```

## Specifications

- Version: 0.23.1
- Platform: Ubuntu 22.10

Pull request:
Fix 1229
Possibly fixes #1229.

Patch:
diff --git a/engine/src/conversion/analysis/fun/mod.rs b/engine/src/conversion/analysis/fun/mod.rs
index 24bfbc85..84829530 100644
--- a/engine/src/conversion/analysis/fun/mod.rs
+++ b/engine/src/conversion/analysis/fun/mod.rs
@@ -1261,7 +1261,10 @@ impl<'a> FnAnalyzer<'a> {
             } else {
                 "_"
             };
-            cxxbridge_name = make_ident(format!("{cxxbridge_name}{joiner}autocxx_wrapper"));
+            cxxbridge_name = make_ident(
+                self.config
+                    .uniquify_name_per_mod(&format!("{cxxbridge_name}{joiner}autocxx_wrapper")),
+            );
             let (payload, cpp_function_kind) = match fun.synthetic_cpp.as_ref().cloned() {
                 Some((payload, cpp_function_kind)) => (payload, cpp_function_kind),
                 None => match kind {
@@ -1487,7 +1490,7 @@ impl<'a> FnAnalyzer<'a> {
                             AsRef < #to_type >
                         },
                         parse_quote! {
-                            &'a mut ::core::pin::Pin < &'a mut #from_type_path >
+                            &'a mut ::std::pin::Pin < &'a mut #from_type_path >
                         },
                         "as_ref",
                     ),
@@ -1496,7 +1499,7 @@ impl<'a> FnAnalyzer<'a> {
                             autocxx::PinMut < #to_type >
                         },
                         parse_quote! {
-                            ::core::pin::Pin < &'a mut #from_type_path >
+                            ::std::pin::Pin < &'a mut #from_type_path >
                         },
                         "pin_mut",
                     ),
diff --git a/engine/src/conversion/analysis/type_converter.rs b/engine/src/conversion/analysis/type_converter.rs
index ada512be..b07d4a75 100644
--- a/engine/src/conversion/analysis/type_converter.rs
+++ b/engine/src/conversion/analysis/type_converter.rs
@@ -478,7 +478,7 @@ impl<'a> TypeConverter<'a> {
                 // be a plain value. We should detect and abort.
                 let mut outer = elem.map(|elem| match mutability {
                     Some(_) => Type::Path(parse_quote! {
-                        ::core::pin::Pin < & #mutability #elem >
+                        ::std::pin::Pin < & #mutability #elem >
                     }),
                     None => Type::Reference(parse_quote! {
                         & #elem
diff --git a/engine/src/conversion/codegen_rs/function_wrapper_rs.rs b/engine/src/conversion/codegen_rs/function_wrapper_rs.rs
index 4afe3c72..9a75a251 100644
--- a/engine/src/conversion/codegen_rs/function_wrapper_rs.rs
+++ b/engine/src/conversion/codegen_rs/function_wrapper_rs.rs
@@ -67,7 +67,7 @@ impl TypeConversionPolicy {
                     _ => panic!("Not a ptr"),
                 };
                 let ty = parse_quote! {
-                    ::core::pin::Pin<&mut ::core::mem::MaybeUninit< #ty >>
+                    ::std::pin::Pin<&mut ::std::mem::MaybeUninit< #ty >>
                 };
                 RustParamConversion::Param {
                     ty,
@@ -84,13 +84,13 @@ impl TypeConversionPolicy {
                     _ => panic!("Not a ptr"),
                 };
                 let ty = parse_quote! {
-                    ::core::pin::Pin<autocxx::moveit::MoveRef< '_, #ty >>
+                    ::std::pin::Pin<autocxx::moveit::MoveRef< '_, #ty >>
                 };
                 RustParamConversion::Param {
                     ty,
                     local_variables: Vec::new(),
                     conversion: quote! {
-                        { let r: &mut _ = ::core::pin::Pin::into_inner_unchecked(#var.as_mut());
+                        { let r: &mut _ = ::std::pin::Pin::into_inner_unchecked(#var.as_mut());
                             r
                         }
                     },
@@ -138,10 +138,10 @@ impl TypeConversionPolicy {
                         ),
                         MaybeUnsafeStmt::binary(
                             quote! { let mut #space_var_name =
-                                unsafe { ::core::pin::Pin::new_unchecked(&mut #space_var_name) };
+                                unsafe { ::std::pin::Pin::new_unchecked(&mut #space_var_name) };
                             },
                             quote! { let mut #space_var_name =
-                                ::core::pin::Pin::new_unchecked(&mut #space_var_name);
+                                ::std::pin::Pin::new_unchecked(&mut #space_var_name);
                             },
                         ),
                         MaybeUnsafeStmt::needs_unsafe(
diff --git a/engine/src/conversion/codegen_rs/lifetime.rs b/engine/src/conversion/codegen_rs/lifetime.rs
index abff3e17..f4f8832c 100644
--- a/engine/src/conversion/codegen_rs/lifetime.rs
+++ b/engine/src/conversion/codegen_rs/lifetime.rs
@@ -160,17 +160,14 @@ enum AddLifetimeError {
 fn add_lifetime_to_pinned_reference(
     segments: &mut Punctuated<PathSegment, syn::token::Colon2>,
 ) -> Result<(), AddLifetimeError> {
-    static EXPECTED_SEGMENTS: &[(&[&str], bool)] = &[
-        (&["std", "core"], false),
-        (&["pin"], false),
-        (&["Pin"], true), // true = act on the arguments of this segment
+    static EXPECTED_SEGMENTS: &[(&str, bool)] = &[
+        ("std", false),
+        ("pin", false),
+        ("Pin", true), // true = act on the arguments of this segment
     ];
 
     for (seg, (expected_name, act)) in segments.iter_mut().zip(EXPECTED_SEGMENTS.iter()) {
-        if !expected_name
-            .iter()
-            .any(|expected_name| seg.ident == expected_name)
-        {
+        if seg.ident != expected_name {
             return Err(AddLifetimeError::WasNotPin);
         }
         if *act {
diff --git a/engine/src/conversion/codegen_rs/mod.rs b/engine/src/conversion/codegen_rs/mod.rs
index 9e4310db..8c709d71 100644
--- a/engine/src/conversion/codegen_rs/mod.rs
+++ b/engine/src/conversion/codegen_rs/mod.rs
@@ -755,7 +755,7 @@ impl<'a> RsCodeGenerator<'a> {
         // TODO it would be nice to impl AsMut here but pin prevents us
         bindgen_mod_items.push(parse_quote! {
             impl super::super::super::#id {
-                pub fn pin_mut(&mut self) -> ::core::pin::Pin<&mut cxxbridge::#super_cxxxbridge_id> {
+                pub fn pin_mut(&mut self) -> ::std::pin::Pin<&mut cxxbridge::#super_cxxxbridge_id> {
                     use autocxx::subclass::CppSubclass;
                     self.peer_mut().#as_mut_id()
                 }
@@ -842,7 +842,7 @@ impl<'a> RsCodeGenerator<'a> {
                         .as_ref()
                         .#borrow()
                         .expect(#reentrancy_panic_msg);
-                    let r = ::core::ops::#deref_ty::#deref_call(& #mut_token b);
+                    let r = ::std::ops::#deref_ty::#deref_call(& #mut_token b);
                     #methods_trait :: #method_name
                         (r,
                         #args)
diff --git a/engine/src/conversion/codegen_rs/non_pod_struct.rs b/engine/src/conversion/codegen_rs/non_pod_struct.rs
index 30ddcb17..24dfece3 100644
--- a/engine/src/conversion/codegen_rs/non_pod_struct.rs
+++ b/engine/src/conversion/codegen_rs/non_pod_struct.rs
@@ -87,7 +87,7 @@ pub(crate) fn make_non_pod(s: &mut ItemStruct, layout: Option<Layout>) {
                 let id = &gpt.ident;
                 let field_name = make_ident(format!("_phantom_{counter}"));
                 let toks = quote! {
-                    #field_name: ::core::marker::PhantomData<::core::cell::UnsafeCell< #id >>
+                    #field_name: ::std::marker::PhantomData<::std::cell::UnsafeCell< #id >>
                 };
                 Some(Field::parse_named.parse2(toks).unwrap())
             }
diff --git a/engine/src/known_types.rs b/engine/src/known_types.rs
index 3917f03f..4f854883 100644
--- a/engine/src/known_types.rs
+++ b/engine/src/known_types.rs
@@ -467,10 +467,10 @@ fn create_type_database() -> TypeDatabase {
     ));
 
     db.insert(TypeDetails::new(
-        "core::pin::Pin",
+        "std::pin::Pin",
         "Pin",
         Behavior::RustByValue, // because this is actually Pin<&something>
-        Some("std::pin::Pin".to_string()),
+        None,
         true,
         false,
     ));
diff --git a/engine/src/output_generators.rs b/engine/src/output_generators.rs
index 09c143ab..a862558c 100644
--- a/engine/src/output_generators.rs
+++ b/engine/src/output_generators.rs
@@ -19,7 +19,7 @@ pub struct RsOutput<'a> {
 
 /// Creates an on-disk archive (actually a JSON file) of the Rust side of the bindings
 /// for multiple `include_cpp` macros. If you use this, you will want to tell
-/// `autocxx_macro` how to find this file using the `AUTOCXX_RS_JSON_ARCHIVE`
+/// `autocxx_macro` how to find this file using the `AUTOCXX_RS_ARCHIVE`
 /// environment variable.
 pub fn generate_rs_archive<'a>(rs_outputs: impl Iterator<Item = RsOutput<'a>>) -> String {
     let mut multi_bindings = MultiBindings::default();
diff --git a/gen/cmd/src/main.rs b/gen/cmd/src/main.rs
index 2bce4350..2855488b 100644
--- a/gen/cmd/src/main.rs
+++ b/gen/cmd/src/main.rs
@@ -132,7 +132,7 @@ fn main() -> miette::Result<()> {
         .arg(
             Arg::new("gen-rs-include")
                 .long("gen-rs-include")
-                .help("whether to generate Rust files for inclusion using autocxx_macro")
+                .help("whether to generate Rust files for inclusion using autocxx_macro (suffix will be .include.rs)")
         )
         .arg(
             Arg::new("gen-rs-archive")
@@ -156,7 +156,7 @@ fn main() -> miette::Result<()> {
         .arg(
             Arg::new("fix-rs-include-name")
                 .long("fix-rs-include-name")
-                .help("Make the name of the .rs file predictable (suffix will be .include.rs). You must set AUTOCXX_RS_FILE during Rust build time to educate autocxx_macro about your choice.")
+                .help("Make the name of the .rs file predictable. You must set AUTOCXX_RS_FILE during Rust build time to educate autocxx_macro about your choice.")
                 .requires("gen-rs-include")
         )
         .arg(


Test patch:
diff --git a/integration-tests/tests/integration_test.rs b/integration-tests/tests/integration_test.rs
index 04be428a..0dd3ad53 100644
--- a/integration-tests/tests/integration_test.rs
+++ b/integration-tests/tests/integration_test.rs
@@ -1282,7 +1282,7 @@ fn test_define_str() {
         #define BOB \"foo\"
     "};
     let rs = quote! {
-        assert_eq!(core::str::from_utf8(ffi::BOB).unwrap().trim_end_matches(char::from(0)), "foo");
+        assert_eq!(std::str::from_utf8(ffi::BOB).unwrap().trim_end_matches(char::from(0)), "foo");
     };
     run_test(cxx, hdr, rs, &["BOB"], &[]);
 }
@@ -1429,7 +1429,7 @@ fn test_asan_working_as_expected_for_cpp_allocations() {
 #[test]
 fn test_asan_working_as_expected_for_rust_allocations() {
     perform_asan_doom_test(
-        quote! { Box::into_raw(core::pin::Pin::into_inner_unchecked(a)) },
+        quote! { Box::into_raw(std::pin::Pin::into_inner_unchecked(a)) },
         quote! { Box },
     )
 }
@@ -3043,7 +3043,7 @@ fn test_string_constant() {
         const char* STRING = \"Foo\";
     "};
     let rs = quote! {
-        let a = core::str::from_utf8(ffi::STRING).unwrap().trim_end_matches(char::from(0));
+        let a = std::str::from_utf8(ffi::STRING).unwrap().trim_end_matches(char::from(0));
         assert_eq!(a, "Foo");
     };
     run_test("", hdr, rs, &["STRING"], &[]);
@@ -8075,10 +8075,10 @@ fn test_pv_subclass_allocation_not_self_owned() {
             assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
             assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
             let obs_superclass = obs.as_ref().unwrap(); // &subclass
-            let obs_superclass = unsafe { core::mem::transmute::<&ffi::MyTestObserverCpp, &ffi::TestObserver>(obs_superclass) };
+            let obs_superclass = unsafe { std::mem::transmute::<&ffi::MyTestObserverCpp, &ffi::TestObserver>(obs_superclass) };
             ffi::TriggerTestObserverA(obs_superclass);
             assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
-            core::mem::drop(obs);
+            std::mem::drop(obs);
             Lazy::force(&STATUS).lock().unwrap().a_called = false;
             assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
             assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
@@ -8095,7 +8095,7 @@ fn test_pv_subclass_allocation_not_self_owned() {
             ffi::TriggerTestObserverA(obs.as_ref().borrow().as_ref());
             assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
             Lazy::force(&STATUS).lock().unwrap().a_called = false;
-            core::mem::drop(obs);
+            std::mem::drop(obs);
             assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
             assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
             assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
@@ -8210,11 +8210,11 @@ fn test_pv_subclass_allocation_self_owned() {
             assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
             assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
             let obs_superclass = obs.as_ref().unwrap(); // &subclass
-            let obs_superclass = unsafe { core::mem::transmute::<&ffi::MyTestObserverCpp, &ffi::TestObserver>(obs_superclass) };
+            let obs_superclass = unsafe { std::mem::transmute::<&ffi::MyTestObserverCpp, &ffi::TestObserver>(obs_superclass) };
 
             ffi::TriggerTestObserverA(obs_superclass);
             assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
-            core::mem::drop(obs);
+            std::mem::drop(obs);
             Lazy::force(&STATUS).lock().unwrap().a_called = false;
             assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
             assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
@@ -8231,7 +8231,7 @@ fn test_pv_subclass_allocation_self_owned() {
 
             assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
             Lazy::force(&STATUS).lock().unwrap().a_called = false;
-            core::mem::drop(obs);
+            std::mem::drop(obs);
             assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
             assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
             assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
@@ -8243,7 +8243,7 @@ fn test_pv_subclass_allocation_self_owned() {
             let obs_superclass_ptr: *const ffi::TestObserver = obs.as_ref().borrow().as_ref();
             // Retain just a pointer on the Rust side, so there is no Rust-side
             // ownership.
-            core::mem::drop(obs);
+            std::mem::drop(obs);
             assert!(Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
             assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
             assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
@@ -9800,8 +9800,8 @@ fn size_and_alignment_test(pod: bool) {
         accumulator.extend(quote! {
             let c_size = ffi::#get_size_symbol();
             let c_align = ffi::#get_align_symbol();
-            assert_eq!(core::mem::size_of::<ffi::#type_symbol>(), c_size);
-            assert_eq!(core::mem::align_of::<ffi::#type_symbol>(), c_align);
+            assert_eq!(std::mem::size_of::<ffi::#type_symbol>(), c_size);
+            assert_eq!(std::mem::align_of::<ffi::#type_symbol>(), c_align);
         });
         accumulator
     });
@@ -11827,6 +11827,47 @@ fn test_issue_1214() {
     run_test("", hdr, quote! {}, &["C"], &[]);
 }
 
+#[test]
+fn test_issue_1229() {
+    let hdr = indoc! {"
+    struct Thing {
+        float id;
+    
+        Thing(float id) : id(id) {}
+    };
+
+    struct Item {
+        float id;
+    
+        Item(float id) : id(id) {}
+    };
+    "};
+    let hexathorpe = Token![#](Span::call_site());
+    let rs = quote! {
+        use autocxx::WithinUniquePtr;
+
+        autocxx::include_cpp! {
+            #hexathorpe include "input.h"
+            name!(thing)
+            safety!(unsafe)
+            generate!("Thing")
+        }
+        autocxx::include_cpp! {
+            #hexathorpe include "input.h"
+            name!(item)
+            safety!(unsafe)
+            generate!("Item")
+        }
+
+        fn main() {
+            let _thing = thing::Thing::new(15.).within_unique_ptr();
+            let _item = item::Item::new(15.).within_unique_ptr();
+        }
+    };
+
+    do_run_test_manual("", hdr, rs, None, None).unwrap();
+}
+
 // Yet to test:
 // - Ifdef
 // - Out param pointers