Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

On Windows in C++ interop mode, the generated C++ header includes internal types #78152

Open
hwjeremy opened this issue Dec 12, 2024 · 0 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. triage needed This issue needs more specific labels

Comments

@hwjeremy
Copy link

hwjeremy commented Dec 12, 2024

Description

When building a target in C++ interop mode on Windows, and generating a Clang header, we expect that only public members will be exposed in the header. It appears that in some circumstances, internal members will also be exposed, causing any compilation including the header to fail.

Reproduction

Consider a target being built for using in a C++ project:

        .target(
            name: "Foo",
            swiftSettings: [
                .interoperabilityMode(.Cxx),
                .unsafeFlags(["-emit-clang-header-path", "Foo.h"])
            ]
        ),

With a type...

public struct Bar {

    let baz: Int
    
    public func qux() -> Void { } 
    
 }

And elsewhere...

extension Bar {

    internal struct Fred {
        let thud: Int
    }

}

On macOS, as expected, our C++ header is generated without any declaration of or reference to Fred, per the C++ interoperability documentation stating that only public symbols are exposed via the C++ header.

On Windows, we see Bar and its method qux are declared as expected. We also see a reference to Fred, as...

  using Fred=Fred;

Visible in the wider context of various Bar declaration, in the public members section:

class SWIFT_SYMBOL("s:8Foo3BarV") Bar final {
public:
  SWIFT_INLINE_THUNK ~Bar() noexcept {
    auto metadata = _impl::$s8Foo3BarVMa(0);
    auto *vwTableAddr = reinterpret_cast<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
#ifdef __arm64e__
    auto *vwTable = reinterpret_cast<swift::_impl::ValueWitnessTable *>(ptrauth_auth_data(reinterpret_cast<void *>(*vwTableAddr), ptrauth_key_process_independent_data, ptrauth_blend_discriminator(vwTableAddr, 11839)));
#else
    auto *vwTable = *vwTableAddr;
#endif
    vwTable->destroy(_getOpaquePointer(), metadata._0);
  }
  SWIFT_INLINE_THUNK Bar(const Bar &other) noexcept {
    auto metadata = _impl::$s8Foo3BarVMa(0);
    auto *vwTableAddr = reinterpret_cast<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
#ifdef __arm64e__
    auto *vwTable = reinterpret_cast<swift::_impl::ValueWitnessTable *>(ptrauth_auth_data(reinterpret_cast<void *>(*vwTableAddr), ptrauth_key_process_independent_data, ptrauth_blend_discriminator(vwTableAddr, 11839)));
#else
    auto *vwTable = *vwTableAddr;
#endif
    vwTable->initializeWithCopy(_getOpaquePointer(), const_cast<char *>(other._getOpaquePointer()), metadata._0);
  }
  SWIFT_INLINE_THUNK Bar &operator =(const Bar &other) noexcept {
    auto metadata = _impl::$s8Foo3BarVMa(0);
    auto *vwTableAddr = reinterpret_cast<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
#ifdef __arm64e__
    auto *vwTable = reinterpret_cast<swift::_impl::ValueWitnessTable *>(ptrauth_auth_data(reinterpret_cast<void *>(*vwTableAddr), ptrauth_key_process_independent_data, ptrauth_blend_discriminator(vwTableAddr, 11839)));
#else
    auto *vwTable = *vwTableAddr;
#endif
    vwTable->assignWithCopy(_getOpaquePointer(), const_cast<char *>(other._getOpaquePointer()), metadata._0);
  return *this;
  }
  SWIFT_INLINE_THUNK Bar &operator =(Bar &&other) = delete;
  [[noreturn]] SWIFT_INLINE_PRIVATE_HELPER Bar(Bar &&) noexcept {
  swift::_impl::_fatalError_Cxx_move_of_Swift_value_type_not_supported_yet();
  swift::_impl::_swift_stdlib_reportFatalError("swift", 5, "C++ does not support moving a Swift value yet", 45, 0);
  abort();
  }
  SWIFT_INLINE_THUNK void qux() const SWIFT_SYMBOL("s:8Foo3BarV3quxyyF");
  using Fred=Fred;
private:
  SWIFT_INLINE_THUNK Bar() noexcept {}
  static SWIFT_INLINE_THUNK Bar _make() noexcept { return Bar(); }
  SWIFT_INLINE_THUNK const char * _Nonnull _getOpaquePointer() const noexcept { return _storage; }
  SWIFT_INLINE_THUNK char * _Nonnull _getOpaquePointer() noexcept { return _storage; }

  alignas(8) char _storage[8];
  friend class _impl::_impl_Bar;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wc++17-extensions"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreserved-identifier"
  typedef char $s8Foo3BarVD;
  static inline constexpr $s8Foo3BarVD __swift_mangled_name = 0;
#pragma clang diagnostic pop
#pragma clang diagnostic pop
};

Expected behavior

We expect Fred to be absent from the generated header.

Environment

Swift version 6.1-dev (LLVM f4b733c38006ec1, Swift 5c7509bef50dbd7)

Additional information

Thank you everyone working on Swift / Windows C++ interoperability... You are enabling wonderful things!

@hwjeremy hwjeremy added bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. triage needed This issue needs more specific labels labels Dec 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. triage needed This issue needs more specific labels
Projects
None yet
Development

No branches or pull requests

1 participant