`import_as_ref` crash on Swift 5.7

I have a class that I am trying to import using C++ interop, MLIRContext. Since we don't bridge initializer for types with custom copy behavior, I'm trying to create a C++ helper library with the following function: inline mlir::MLIRContext *Create() { return new mlir::MLIRContext(); } (would be great if this was automatically synthesized for UnsafeMutablePointer<mlir.MLIRContext>!).

Without import_as_ref it comes in as Optional<OpaquePointer>, and kind-of works, modulo dealing with the fact that this thing is an OpaquePointer. If I try to use import_as_ref (specifically, __attribute__((swift_attr("import_as_ref"))) __attribute__((swift_attr("retain:immortal"))) __attribute__((swift_attr("release:immortal"))), the released 5.7 compiler crashes with the following error:

build] error: compile command failed due to signal 6 (use -v to see invocation)
[build] Attribute after last parameter!
[build]   %1 = call %"class.mlir::MLIRContext"* @_ZN5circt11SwiftBridge11MLIRContext6CreateEv(), !dbg !64
[build] in function $s10CIRCTSwift17createMLIRContextSo4mlirO0C0VyF
[build] <unknown>:0: error: fatal error encountered during compilation; please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the project
[build] <unknown>:0: note: Broken function found, compilation aborted!
[build] Please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the project and the crash backtrace.
[build] Stack dump:
[build] 0.	Program arguments: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-frontend -frontend -c -primary-file /Volumes/Shared/Developer/Projects/circt-workspace/circt/lib/Bindings/Swift/Module/MLIRContext.swift -emit-module-path tools/circt/lib/Bindings/Swift/Module/CMakeFiles/CIRCTSwift.dir/MLIRContext.swift.swiftmodule -emit-module-doc-path tools/circt/lib/Bindings/Swift/Module/CMakeFiles/CIRCTSwift.dir/MLIRContext.swift.swiftdoc -emit-module-source-info-path tools/circt/lib/Bindings/Swift/Module/CMakeFiles/CIRCTSwift.dir/MLIRContext.swift.swiftsourceinfo -emit-dependencies-path tools/circt/lib/Bindings/Swift/Module/CMakeFiles/CIRCTSwift.dir/MLIRContext.swift.o.d -emit-reference-dependencies-path tools/circt/lib/Bindings/Swift/Module/CMakeFiles/CIRCTSwift.dir/MLIRContext.swift.o.swiftdeps -target x86_64-apple-macosx13.0 -enable-objc-interop -stack-check -enable-cxx-interop -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk -I /Volumes/Shared/Developer/Projects/circt-workspace/build/tools/circt/lib/Bindings/Swift/Module -I /Volumes/Shared/Developer/Projects/circt-workspace/circt/lib/Bindings/Swift/Module -I /Volumes/Shared/Developer/Projects/circt-workspace/build/include -I /Volumes/Shared/Developer/Projects/circt-workspace/circt/llvm/llvm/include -I /Volumes/Shared/Developer/Projects/circt-workspace/circt/include -I /Volumes/Shared/Developer/Projects/circt-workspace/build/tools/circt/include -I /Volumes/Shared/Developer/Projects/circt-workspace/circt/llvm/mlir/include -I /Volumes/Shared/Developer/Projects/circt-workspace/build/tools/mlir/include -g -module-link-name CIRCTSwift -D _DEBUG -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -new-driver-path /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-driver -empty-abi-descriptor -resource-dir /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift -enable-anonymous-context-mangled-names -Xcc -std=c++17 -module-name CIRCTSwift -disable-clang-spi -target-sdk-version 12.3 -parse-as-library -o tools/circt/lib/Bindings/Swift/Module/CMakeFiles/CIRCTSwift.dir/MLIRContext.swift.o
[build] 1.	Apple Swift version 5.7 (swiftlang-5.7.0.127.4 clang-1400.0.29.50)
[build] 2.	Compiling with the current language version
[build] 3.	Running pass 'Module Verifier' on function '@"$s10CIRCTSwift17createMLIRContextSo4mlirO0C0VyF"'
[build] 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):
[build] 0  swift-frontend           0x0000000113caa7f7 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 39
[build] 1  swift-frontend           0x0000000113ca9828 llvm::sys::RunSignalHandlers() + 248
[build] 2  swift-frontend           0x0000000113caae10 SignalHandler(int) + 288
[build] 3  libsystem_platform.dylib 0x00007ff815f8fc1d _sigtramp + 29
[build] 4  libsystem_malloc.dylib   0x00007ff815dbc006 free_tiny + 515
[build] 5  libsystem_c.dylib        0x00007ff815eaeca5 abort + 123
[build] 6  swift-frontend           0x000000010e872408 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*)::$_3::__invoke(void*, char const*, bool) + 728
[build] 7  swift-frontend           0x0000000113bf136d llvm::report_fatal_error(llvm::Twine const&, bool) + 397
[build] 8  swift-frontend           0x0000000113bf11d9 llvm::report_fatal_error(char const*, bool) + 41
[build] 9  swift-frontend           0x0000000113a4f89f (anonymous namespace)::VerifierLegacyPass::runOnFunction(llvm::Function&) + 111
[build] 10 swift-frontend           0x00000001139e3d30 llvm::FPPassManager::runOnFunction(llvm::Function&) + 1488
[build] 11 swift-frontend           0x00000001139e34b1 llvm::legacy::FunctionPassManagerImpl::run(llvm::Function&) + 113
[build] 12 swift-frontend           0x00000001139ea889 llvm::legacy::FunctionPassManager::run(llvm::Function&) + 329
[build] 13 swift-frontend           0x000000010ecafb08 swift::performLLVMOptimizations(swift::IRGenOptions const&, llvm::Module*, llvm::TargetMachine*) + 2248
[build] 14 swift-frontend           0x000000010ecb143d swift::performLLVM(swift::IRGenOptions const&, swift::DiagnosticEngine&, llvm::sys::SmartMutex<false>*, llvm::GlobalVariable*, llvm::Module*, llvm::TargetMachine*, llvm::StringRef, swift::UnifiedStatsReporter*) + 2717
[build] 15 swift-frontend           0x000000010e868173 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*) + 3843
[build] 16 swift-frontend           0x000000010e8699b5 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 5701
[build] 17 swift-frontend           0x000000010e7ff8ea swift::mainEntry(int, char const**) + 3082
[build] 18 dyld                     0x00007ff815c34310 start + 2432
[build] ninja: build stopped: subcommand failed.

Any thoughts on what is happening here?

5.7 has limited support for import_reference. Please try the latest 5.8 toolchain instead.

1 Like

With 5.8 I'm getting a different error:

[build] /workspaces/circt-workspace/circt/test/Bindings/Swift/Bindings.swift:19:15: error: 'createMLIRContext' is inaccessible due to '@_spi' protection level
[build] let context = createMLIRContext()
[build]               ^

My current setup is I have a C++ library in cmake where I bridge what effectively would be new MLIRContext() for the imported-as-ref MLIRContext. I then have my Swift library (CIRCTSwift) which depends on this which wraps that functionality in a Swift API (currently just a function, but eventually an extension on MLIRContext, implementing what would effectively be new MLIRContext())

public func createMLIRContext() -> mlir.MLIRContext {
  /// A call to the C++ function 
  /// inline mlir::MLIRContext *Create() {
  ///  return new mlir::MLIRContext();
  /// }
  circt.SwiftBridge.MLIRContext.Create()
}

I then have a test library which depends on CIRCTSwift which calls that function, which has the let context = createMLIRContext(). Looks like for some reason createMLIRContext() is getting a weird visibility level.

Seems like this may be relating to createMLIRContext returning a C++ type... was this something @egor.zhdan was working on?

error: 'createMLIRContext' is inaccessible due to '@_spi' protection level

This looks like a bug, we'll need to investigate. Thanks for sharing the steps to reproduce!

@George if you could file an issue on GitHub to track this bug, it would be great

Filed here: Unexpected `@_spi` visibility for public function returning C++ type · Issue #61472 · apple/swift · GitHub

1 Like

It seems one workaround to this is to force the C++ clang module to be loaded earlier (or, from my testing, making sure each of the types from that module is loaded earlier).

Would it be possible/simpler to just do @_spi(<somethingGoesHere>) import CIRCTSwift in the meantime? What would be the <somethingGoesHere>?

as far as I understand that wouldn't help - the error is emitted by the diagnostic pass, but the underlying issue happens as the function in the Swift module is not imported because the C++ type isn't loaded from the Clang module, which an @spi annotation on an import won't fix.