Skip to content

Commit b509551

Browse files
committed
[cxx-interop] Clone all of the attributes from base method correctly
If a C++ `struct Base` declares a method with a Clang attribute that Swift is able to import, and `struct Derived` inherits from `Base`, the method should get cloned from `Base` to `Derived` with its attributes. Previously we were only cloning one attribute at most due to a bug in `cloneImportedAttributes`. DeclAttributes is an intrusively linked list, and it was being made invalid while iterating over it: `otherDecl->getAttrs().add(attrs)` iterates over the list and calls `otherDecl->add(eachElement)`, which invalidates the iterator after the first iteration.
1 parent 71c81d5 commit b509551

File tree

3 files changed

+12
-11
lines changed

3 files changed

+12
-11
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5699,9 +5699,10 @@ makeBaseClassMemberAccessors(DeclContext *declContext,
56995699
}
57005700

57015701
// Clone attributes that have been imported from Clang.
5702-
DeclAttributes cloneImportedAttributes(ValueDecl *decl, ASTContext &context) {
5703-
auto attrs = DeclAttributes();
5704-
for (auto attr : decl->getAttrs()) {
5702+
void cloneImportedAttributes(ValueDecl *fromDecl, ValueDecl* toDecl) {
5703+
ASTContext& context = fromDecl->getASTContext();
5704+
DeclAttributes& attrs = toDecl->getAttrs();
5705+
for (auto attr : fromDecl->getAttrs()) {
57055706
switch (attr->getKind()) {
57065707
case DeclAttrKind::Available: {
57075708
attrs.add(cast<AvailableAttr>(attr)->clone(context, true));
@@ -5739,8 +5740,6 @@ DeclAttributes cloneImportedAttributes(ValueDecl *decl, ASTContext &context) {
57395740
break;
57405741
}
57415742
}
5742-
5743-
return attrs;
57445743
}
57455744

57465745
static ValueDecl *
@@ -5770,8 +5769,7 @@ cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext) {
57705769
fn->getThrownInterfaceType(),
57715770
fn->getGenericParams(), fn->getParameters(),
57725771
fn->getResultInterfaceType(), newContext);
5773-
auto inheritedAttributes = cloneImportedAttributes(decl, context);
5774-
out->getAttrs().add(inheritedAttributes);
5772+
cloneImportedAttributes(decl, out);
57755773
out->copyFormalAccessFrom(fn);
57765774
out->setBodySynthesizer(synthesizeBaseClassMethodBody, fn);
57775775
out->setSelfAccessKind(fn->getSelfAccessKind());

test/Interop/Cxx/class/inheritance/Inputs/functions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ struct Base {
5454
return i * 2;
5555
}
5656

57-
void pure() const __attribute__((pure)) {}
57+
int pure() const __attribute__((pure)) { return 123; }
5858

5959
inline int sameMethodNameSameSignature() const {
6060
return 42;

test/Interop/Cxx/class/inheritance/functions-module-interface.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030
// CHECK-NEXT: mutating func swiftRenamed(input i: Int32) -> Int32
3131
// CHECK-NEXT: @available(swift, obsoleted: 3, renamed: "swiftRenamed(input:)")
3232
// CHECK-NEXT: mutating func renamed(_ i: Int32) -> Int32
33-
// CHECK-NEXT: @_effects(readonly) func pure()
33+
// CHECK-NEXT: @discardableResult
34+
// CHECK-NEXT: @_effects(readonly) func pure() -> Int32
3435
// CHECK-NEXT: @discardableResult
3536
// CHECK-NEXT: func sameMethodNameSameSignature() -> Int32
3637
// CHECK-NEXT: @discardableResult
@@ -65,7 +66,8 @@
6566
// CHECK-NEXT: mutating func swiftRenamed(input i: Int32) -> Int32
6667
// CHECK-NEXT: @available(swift, obsoleted: 3, renamed: "swiftRenamed(input:)")
6768
// CHECK-NEXT: mutating func renamed(_ i: Int32) -> Int32
68-
// CHECK-NEXT: @_effects(readonly) func pure()
69+
// CHECK-NEXT: @discardableResult
70+
// CHECK-NEXT: @_effects(readonly) func pure() -> Int32
6971
// CHECK-NEXT: @discardableResult
7072
// CHECK-NEXT: func sameMethodDifferentSignature() -> Int32
7173
// CHECK-NEXT: @discardableResult
@@ -96,7 +98,8 @@
9698
// CHECK-NEXT: mutating func swiftRenamed(input i: Int32) -> Int32
9799
// CHECK-NEXT: @available(swift, obsoleted: 3, renamed: "swiftRenamed(input:)")
98100
// CHECK-NEXT: mutating func renamed(_ i: Int32) -> Int32
99-
// CHECK-NEXT: @_effects(readonly) func pure()
101+
// CHECK-NEXT: @discardableResult
102+
// CHECK-NEXT: @_effects(readonly) func pure() -> Int32
100103
// CHECK-NEXT: @discardableResult
101104
// CHECK-NEXT: func sameMethodDifferentSignature() -> Int32
102105
// CHECK-NEXT: @discardableResult

0 commit comments

Comments
 (0)