Skip to content

[cxx-interop] Skip type metadata for C++ types that are only used in private C++ fields #78467

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

Merged
merged 1 commit into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions lib/IRGen/GenReflection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,15 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {

B.addInt32(getNumFields(NTD));
forEachField(IGM, NTD, [&](Field field) {
// Skip private C++ fields that were imported as private Swift fields.
// The type of a private field might not have all the type witness
// operations that Swift requires, for instance,
// `std::unique_ptr<IncompleteType>` would not have a destructor.
if (field.getKind() == Field::Kind::Var &&
field.getVarDecl()->getClangDecl() &&
field.getVarDecl()->getFormalAccess() == AccessLevel::Private)
return;

addField(field);
});
}
Expand Down
6 changes: 6 additions & 0 deletions test/Interop/Cxx/class/Inputs/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,9 @@ module Closure {
header "closure.h"
requires cplusplus
}

module PIMPL {
header "pimpl.h"
requires cplusplus
export *
}
24 changes: 24 additions & 0 deletions test/Interop/Cxx/class/Inputs/pimpl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include <memory>

// C++ types that use pointer-to-implementation idiom.

struct HasPIMPL {
private:
struct I;
I *ptr;
};

HasPIMPL createHasPIMPL();

struct HasSmartPIMPL {
private:
struct I;
std::unique_ptr<I> smart_ptr;

public:
HasSmartPIMPL();
HasSmartPIMPL(const HasSmartPIMPL &other);
~HasSmartPIMPL();
};

HasSmartPIMPL createHasSmartPIMPL();
15 changes: 15 additions & 0 deletions test/Interop/Cxx/class/pimpl-irgen.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// RUN: %target-swiftxx-frontend -emit-irgen %s -I %S/Inputs | %FileCheck %s

// Make sure Swift handles the C++ pointer-to-implementation idiom properly.

import PIMPL

// Trigger type metadata to be emitted by conforming C++ types to a Swift protocol.
protocol MyProto {}
extension HasPIMPL : MyProto {}
extension HasSmartPIMPL : MyProto {}

let _ = createHasPIMPL()
let _ = createHasSmartPIMPL()

// CHECK-NOT: @"get_type_metadata {{.*}}default_delete{{.*}}
14 changes: 14 additions & 0 deletions test/Interop/Cxx/class/pimpl-module-interface.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: %target-swift-ide-test -print-module -module-to-print=PIMPL -print-access -I %S/Inputs -cxx-interoperability-mode=default -source-filename=x | %FileCheck %s

// FIXME: We can't import std::unique_ptr properly on Windows (https://github.com/apple/swift/issues/70226)
// XFAIL: OS=windows-msvc

// CHECK: public struct HasPIMPL {
// CHECK-NEXT: public init()
// CHECK-NEXT: private var ptr: OpaquePointer!
// CHECK-NEXT: }

// CHECK: public struct HasSmartPIMPL {
// CHECK-NEXT: public init()
// CHECK-NEXT: private var smart_ptr: std.
// CHECK-NEXT: }