When calling a Swift function that takes two callbacks with arguments, the Swift compiler crashes

I am trying to call a Swift function that takes two callbacks, each with one argument - from C++.
When doing that, the Swift compiler crashes with a Remangling failed error.

Here's my code:

  • C++ header used from Swift and C++:

    namespace my_cpp {
      struct First {
        double value;
      }
      struct Second {
        bool value;
      }
    
      using First_cb = std::function<void(const First&)>;
      using Second_cb = std::function<void(const Second&)>;
    }
    
  • Swift function (called from C++)

    public func hello(first: my_cpp.First_cb   /* std::function */,
                      second: my_cpp.Second_cb /* std::function */) {
      first.callAsFunction(my_cpp.First(value: 3.14))
      second.callAsFunction(my_cpp.Second(value: true))
    }
    
  • C++ function (calling the Swift function)

    void run() {
      MySwift::hello([](const First&) { }, [](const Second&) {});
    }
    

And here's the compiler crash:

SwiftEmitModule normal arm64 Emitting\ module\ for\ NitroTest (in target 'NitroTest' from project 'Pods')

Remangling failed:
original     = $s9NitroTest06HybridB25ObjectSwiftKotlinSpec_cxxC19callbackBothStructs5first6secondSo7margeloO5nitroO0018ResultVoid_tGJAcCaVSo3stdO3__1O0032function_Void_jEEEdaJjatgIevqvbgV_ApQVtF
remangled    = $s9NitroTest06HybridB25ObjectSwiftKotlinSpec_cxxC19callbackBothStructs5first6secondSo7margeloO5nitroO0018ResultVoid_tGJAcCaVSo3stdO3__1O0032function_Void_jEEEdaJjatgIevqvbgV_ARtF
Please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the crash backtrace.
Stack dump:
…………
1.	Apple Swift version 6.1.2 (swiftlang-6.1.2.1.2 clang-1700.0.13.5)
2.	Compiling with effective version 5.10
3.	While evaluating request ExecuteSILPipelineRequest(Run pipelines { Non-Diagnostic Mandatory Optimizations, Serialization, Rest of Onone } on SIL for NitroTest)
4.	While running pass #877 SILModuleTransform "SerializeSILPass".
5.	While evaluating request USRGenerationRequest(NitroTest.(file).HybridTestObjectSwiftKotlinSpec_cxx.callbackBothStructs(first:second:)@/Users/mrousavy/Projects/react-native-nitro/packages/react-native-nitro-test/nitrogen/generated/ios/swift/HybridTestObjectSwiftKotlinSpec_cxx.swift:1189:21)
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0  swift-frontend           0x00000001091e6e24 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 56
1  swift-frontend           0x00000001091e4c5c llvm::sys::RunSignalHandlers() + 112
2  swift-frontend           0x00000001091e7460 SignalHandler(int) + 360
3  libsystem_platform.dylib 0x00000001939a8624 _sigtramp + 56
4  libsystem_pthread.dylib  0x000000019396e88c pthread_kill + 296
5  libsystem_c.dylib        0x0000000193877c60 abort + 124
6  swift-frontend           0x0000000104b4d300 swift::Mangle::Mangler::verify(llvm::StringRef) + 868
7  swift-frontend           0x0000000104781004 swift::Mangle::ASTMangler::mangleDeclAsUSR(swift::ValueDecl const*, llvm::StringRef) + 108
8  swift-frontend           0x0000000104b2a4dc swift::USRGenerationRequest::evaluate(swift::Evaluator&, swift::ValueDecl const*) const + 1032
9  swift-frontend           0x00000001031be120 swift::USRGenerationRequest::OutputType swift::Evaluator::getResultUncached<swift::USRGenerationRequest, swift::USRGenerationRequest::OutputType swift::evaluateOrDefault<swift::USRGenerationRequest>(swift::Evaluator&, swift::USRGenerationRequest, swift::USRGenerationRequest::OutputType)::'lambda'()>(swift::USRGenerationRequest const&, swift::USRGenerationRequest::OutputType swift::evaluateOrDefault<swift::USRGenerationRequest>(swift::Evaluator&, swift::USRGenerationRequest, swift::USRGenerationRequest::OutputType)::'lambda'()) + 660
10 swift-frontend           0x00000001031bdd78 swift::USRGenerationRequest::OutputType swift::Evaluator::getResultCached<swift::USRGenerationRequest, swift::USRGenerationRequest::OutputType swift::evaluateOrDefault<swift::USRGenerationRequest>(swift::Evaluator&, swift::USRGenerationRequest, swift::USRGenerationRequest::OutputType)::'lambda'(), (void*)0>(swift::USRGenerationRequest const&, swift::USRGenerationRequest::OutputType swift::evaluateOrDefault<swift::USRGenerationRequest>(swift::Evaluator&, swift::USRGenerationRequest, swift::USRGenerationRequest::OutputType)::'lambda'()) + 368
11 swift-frontend           0x0000000104b2b030 swift::ide::printValueDeclUSR(swift::ValueDecl const*, llvm::raw_ostream&) + 132
12 swift-frontend           0x000000010387e2c4 (anonymous namespace)::BasicDeclLocsTableWriter::walkToDeclPre(swift::Decl*) + 304
13 swift-frontend           0x00000001047ffd3c (anonymous namespace)::Traversal::doIt(swift::Decl*) + 292
14 swift-frontend           0x0000000104805654 (anonymous namespace)::Traversal::visitNominalTypeDecl(swift::NominalTypeDecl*) + 288
15 swift-frontend           0x00000001048047bc (anonymous namespace)::Traversal::visit(swift::Decl*) + 112
16 swift-frontend           0x00000001047ffd70 (anonymous namespace)::Traversal::doIt(swift::Decl*) + 344
17 swift-frontend           0x00000001049f03b0 swift::SourceFile::walk(swift::ASTWalker&) + 160
18 swift-frontend           0x000000010387b8a4 swift::serialization::writeSourceInfoToStream(llvm::raw_ostream&, llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>) + 3700
19 swift-frontend           0x0000000103427730 bool llvm::function_ref<bool (llvm::raw_pwrite_stream&)>::callback_fn<swift::serialize(llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, swift::SerializationOptions const&, swift::symbolgraphgen::SymbolGraphOptions const&, swift::SILModule const*, swift::fine_grained_dependencies::SourceFileDepGraph const*)::$_2>(long, llvm::raw_pwrite_stream&) + 236
20 swift-frontend           0x0000000102fe85b4 swift::withOutputPath(swift::DiagnosticEngine&, llvm::vfs::OutputBackend&, llvm::StringRef, llvm::function_ref<bool (llvm::raw_pwrite_stream&)>) + 332
21 swift-frontend           0x000000010342713c swift::serialize(llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, swift::SerializationOptions const&, swift::symbolgraphgen::SymbolGraphOptions const&, swift::SILModule const*, swift::fine_grained_dependencies::SourceFileDepGraph const*) + 932
22 swift-frontend           0x000000010303e3f0 bool llvm::function_ref<bool (swift::fine_grained_dependencies::SourceFileDepGraph&&)>::callback_fn<performCompileStepsPostSILGen(swift::CompilerInstance&, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule>>, llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, swift::PrimarySpecificPaths const&, int&, swift::FrontendObserver*)::$_0::operator()() const::'lambda'(swift::fine_grained_dependencies::SourceFileDepGraph&&)>(long, swift::fine_grained_dependencies::SourceFileDepGraph&&) + 40
23 swift-frontend           0x00000001049b979c swift::fine_grained_dependencies::withReferenceDependencies(llvm::PointerUnion<swift::ModuleDecl const*, swift::SourceFile const*>, swift::DependencyTracker const&, llvm::vfs::OutputBackend&, llvm::StringRef, bool, llvm::function_ref<bool (swift::fine_grained_dependencies::SourceFileDepGraph&&)>) + 156
24 swift-frontend           0x000000010303e384 std::__1::__function::__func<performCompileStepsPostSILGen(swift::CompilerInstance&, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule>>, llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, swift::PrimarySpecificPaths const&, int&, swift::FrontendObserver*)::$_0, std::__1::allocator<performCompileStepsPostSILGen(swift::CompilerInstance&, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule>>, llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, swift::PrimarySpecificPaths const&, int&, swift::FrontendObserver*)::$_0>, void ()>::operator()() + 260
25 swift-frontend           0x0000000104027c58 SerializeSILPass::run() + 80
26 swift-frontend           0x0000000103ed447c swift::SILPassManager::executePassPipelinePlan(swift::SILPassPipelinePlan const&) + 13536
27 swift-frontend           0x0000000103f0eedc swift::SimpleRequest<swift::ExecuteSILPipelineRequest, std::__1::tuple<> (swift::SILPipelineExecutionDescriptor), (swift::RequestFlags)1>::evaluateRequest(swift::ExecuteSILPipelineRequest const&, swift::Evaluator&) + 52
28 swift-frontend           0x0000000103ef296c swift::ExecuteSILPipelineRequest::OutputType swift::Evaluator::getResultUncached<swift::ExecuteSILPipelineRequest, swift::ExecuteSILPipelineRequest::OutputType swift::evaluateOrFatal<swift::ExecuteSILPipelineRequest>(swift::Evaluator&, swift::ExecuteSILPipelineRequest)::'lambda'()>(swift::ExecuteSILPipelineRequest const&, swift::ExecuteSILPipelineRequest::OutputType swift::evaluateOrFatal<swift::ExecuteSILPipelineRequest>(swift::Evaluator&, swift::ExecuteSILPipelineRequest)::'lambda'()) + 412
29 swift-frontend           0x0000000103ef63bc swift::runSILPassesForOnone(swift::SILModule&) + 184
30 swift-frontend           0x00000001033f8830 swift::CompilerInstance::performSILProcessing(swift::SILModule*) + 528
31 swift-frontend           0x0000000103038d90 performCompileStepsPostSILGen(swift::CompilerInstance&, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule>>, llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, swift::PrimarySpecificPaths const&, int&, swift::FrontendObserver*) + 1360
32 swift-frontend           0x000000010303871c swift::performCompileStepsPostSema(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 2688
33 swift-frontend           0x000000010303b654 performCompile(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 1764
34 swift-frontend           0x0000000103039fd8 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 3716
35 swift-frontend           0x0000000102fbe0bc swift::mainEntry(int, char const**) + 5428
36 dyld                     0x00000001935ceb98 start + 6076

Now here is where it gets really interesting; if I make the argument inside Second_cb a copy-by-value type instead of const-reference, it successfully builds:

 namespace my_cpp {
   struct First {
     double value;
   }
   struct Second {
     bool value;
   } 

   using First_cb = std::function<void(const First&)>;
-  using Second_cb = std::function<void(const Second&)>;
+  using Second_cb = std::function<void(Second)>;
 }

Has anyone seen something like this before? I would love to help fix the bug, but I can't really find my way around the Swift compiler codebase - does anyone have some pointers in where to look for these type of things?

1 Like