Skip to content

Commit 45b2254

Browse files
committed
[cxx-interop] Propagate CONFORMS_TO attribute to derived classes
If `struct Base` is a public base class of `struct Derived`, and `Base` is annotated with `__attribute__((swift_attr("conforms_to:MyModule.MyProto")))`, `Derived` will now also get a conformance to `MyProto`. rdar://113971944
1 parent 8c049fd commit 45b2254

File tree

3 files changed

+52
-3
lines changed

3 files changed

+52
-3
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2812,13 +2812,24 @@ namespace {
28122812
}
28132813

28142814
if (auto *ntd = dyn_cast<NominalTypeDecl>(result))
2815-
addExplicitProtocolConformances(ntd);
2815+
addExplicitProtocolConformances(ntd, decl);
28162816

28172817
return result;
28182818
}
28192819

2820-
void addExplicitProtocolConformances(NominalTypeDecl *decl) {
2821-
auto clangDecl = decl->getClangDecl();
2820+
void
2821+
addExplicitProtocolConformances(NominalTypeDecl *decl,
2822+
const clang::CXXRecordDecl *clangDecl) {
2823+
if (Impl.isCxxInteropCompatVersionAtLeast(
2824+
version::getUpcomingCxxInteropCompatVersion())) {
2825+
// Propagate conforms_to attribute from public base classes.
2826+
for (auto base : clangDecl->bases()) {
2827+
if (base.getAccessSpecifier() != clang::AccessSpecifier::AS_public)
2828+
continue;
2829+
if (auto *baseClangDecl = base.getType()->getAsCXXRecordDecl())
2830+
addExplicitProtocolConformances(decl, baseClangDecl);
2831+
}
2832+
}
28222833

28232834
if (!clangDecl->hasAttrs())
28242835
return;

test/Interop/Cxx/class/Inputs/conforms-to.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,19 @@ struct
2222
void testImported() const;
2323
};
2424

25+
struct DerivedFromHasTest : HasTest {};
26+
struct DerivedFromDerivedFromHasTest : HasTest {};
27+
28+
struct __attribute__((swift_attr("conforms_to:SwiftTest.Testable")))
29+
DerivedFromDerivedFromHasTestWithDuplicateArg : HasTest {};
30+
31+
struct DerivedFromHasPlay : HasPlay {};
32+
struct DerivedFromDerivedFromHasPlay : HasPlay {};
33+
34+
struct HasTestAndPlay : HasPlay, HasTest {};
35+
struct DerivedFromHasTestAndPlay : HasPlay, HasTest {};
36+
37+
struct DerivedFromHasImportedConf : HasImportedConf {};
38+
struct DerivedFromDerivedFromHasImportedConf : HasImportedConf {};
39+
2540
#endif // TEST_INTEROP_CXX_CLASS_INPUTS_DESTRUCTORS_H

test/Interop/Cxx/class/conforms-to.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// RUN: %target-swift-frontend %S/Inputs/conforms-to-imported.swift -module-name ImportedModule -emit-module -emit-module-path %t/ImportedModule.swiftmodule
33

44
// RUN: %target-typecheck-verify-swift -verify-ignore-unknown -I %t -I %S/Inputs -module-name SwiftTest -enable-experimental-cxx-interop
5+
// RUN: %target-typecheck-verify-swift -verify-ignore-unknown -I %t -I %S/Inputs -module-name SwiftTest -cxx-interoperability-mode=upcoming-swift -D UPCOMING_SWIFT
56

67
import ConformsTo
78
import ImportedModule
@@ -21,6 +22,11 @@ func callee(_ _: Testable) {
2122
func caller(_ x: HasTest) {
2223
callee(x)
2324
}
25+
#if UPCOMING_SWIFT
26+
func caller(_ x: DerivedFromHasTest) { callee(x) }
27+
func caller(_ x: DerivedFromDerivedFromHasTest) { callee(x) }
28+
func caller(_ x: DerivedFromDerivedFromHasTestWithDuplicateArg) { callee(x) }
29+
#endif
2430

2531
func callee(_ _: Playable) {
2632

@@ -29,10 +35,27 @@ func callee(_ _: Playable) {
2935
func caller(_ x: Playable) {
3036
callee(x)
3137
}
38+
#if UPCOMING_SWIFT
39+
func caller(_ x: DerivedFromHasPlay) { callee(x) }
40+
func caller(_ x: DerivedFromDerivedFromHasPlay) { callee(x) }
41+
42+
func caller(_ x: HasTestAndPlay) {
43+
callee(x as Testable)
44+
callee(x as Playable)
45+
}
46+
func caller(_ x: DerivedFromHasTestAndPlay) {
47+
callee(x as Testable)
48+
callee(x as Playable)
49+
}
50+
#endif
3251

3352
func callee(_ _: ProtocolFromImportedModule) {
3453
}
3554

3655
func caller(_ x: HasImportedConf) {
3756
callee(x)
3857
}
58+
#if UPCOMING_SWIFT
59+
func caller(_ x: DerivedFromHasImportedConf) { callee(x) }
60+
func caller(_ x: DerivedFromDerivedFromHasImportedConf) { callee(x) }
61+
#endif

0 commit comments

Comments
 (0)