C++ interop: Function uses foreign reference type error with std::string

Hello swift users!

We have custom build system to build our swift project, and I tried to use new cxx interop feature.
I have simple c++ code

class Foo {
public:
  Foo() = default;

  std::string getStr() const;
};

And I'm calling it from swift like this:

public func getStr() -> String {
  Foo().getStr()
}

Error I'm getting:

SwiftFile.swift:25:9: error: value of type 'Foo' has no member 'getStr'
  Foo().getStr()
  ~~~~~ ^~~~~~
Header.h:25:3: note: function 'getStr' unavailable (cannot import)
  std::string getStr() const;
  ^
Header.h:25:3: note: return type unavailable (cannot import)
  std::string getStr() const;
  ^
Header.h:25:15: note: function uses foreign reference type 'basic_string' as a value in the return types which breaks 'swift_shared_reference' contract
  std::string getStr() const;
              ^

I'm passing -cxx-interoperability-mode=default -Xcc -std=gnu++20 flags to swift compiler.

Setting up the same code in xcode works fine.

Can anyone tell me what I'm doing wrong or perhaps suggest a direction in which to look?

1 Like

After looking into it, I've found the problem.

It's about using export * in the module map files that Xcode creates. Our project uses stricter rules, meaning module maps don't share their dependencies automatically.

Instead of using export *, we found that making the module map only exporting the std module works just fine.

I'm not totally sure how it works, but it looks like when Swift imports a C++ module, it switches out the regular standard library module map for its own version. We couldn't find a better way to deal with this besides changing the module map of the module we're bringing in.