Skip to content

Commit d48c5fb

Browse files
authored
Merge pull request #59022 from skrtks/cxx_inherited_attributes
2 parents c368d73 + e73bb6f commit d48c5fb

File tree

4 files changed

+112
-2
lines changed

4 files changed

+112
-2
lines changed

include/swift/AST/Attr.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,6 +1271,13 @@ class EffectsAttr : public DeclAttribute {
12711271
static bool classof(const DeclAttribute *DA) {
12721272
return DA->getKind() == DAK_Effects;
12731273
}
1274+
1275+
EffectsAttr *clone(ASTContext &ctx) const {
1276+
if (getKind() == EffectsKind::Custom) {
1277+
return new (ctx) EffectsAttr(customString);
1278+
}
1279+
return new (ctx) EffectsAttr(getKind());
1280+
}
12741281
};
12751282

12761283

@@ -2310,6 +2317,13 @@ class DeclAttributes {
23102317
DeclAttrs = Attr;
23112318
}
23122319

2320+
/// Add multiple constructed DeclAttributes to this list.
2321+
void add(DeclAttributes &Attrs) {
2322+
for (auto attr : Attrs) {
2323+
add(attr);
2324+
}
2325+
}
2326+
23132327
// Iterator interface over DeclAttribute objects.
23142328
class iterator : public iterator_base<DeclAttribute, iterator> {
23152329
public:

lib/ClangImporter/ClangImporter.cpp

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4871,6 +4871,51 @@ makeBaseClassMemberAccessors(DeclContext *declContext,
48714871
return {getterDecl, setterDecl};
48724872
}
48734873

4874+
// Clone attributes that have been imported from Clang.
4875+
DeclAttributes cloneImportedAttributes(ValueDecl *decl, ASTContext &context) {
4876+
auto attrs = DeclAttributes();
4877+
for (auto attr : decl->getAttrs()) {
4878+
switch (attr->getKind()) {
4879+
case DAK_Available: {
4880+
attrs.add(cast<AvailableAttr>(attr)->clone(context, true));
4881+
break;
4882+
}
4883+
case DAK_Custom: {
4884+
if (CustomAttr *cAttr = cast<CustomAttr>(attr)) {
4885+
attrs.add(CustomAttr::create(context, SourceLoc(), cAttr->getTypeExpr(),
4886+
cAttr->getInitContext(), cAttr->getArgs(),
4887+
true));
4888+
}
4889+
break;
4890+
}
4891+
case DAK_DiscardableResult: {
4892+
attrs.add(new (context) DiscardableResultAttr(true));
4893+
break;
4894+
}
4895+
case DAK_Effects: {
4896+
attrs.add(cast<EffectsAttr>(attr)->clone(context));
4897+
break;
4898+
}
4899+
case DAK_Final: {
4900+
attrs.add(new (context) FinalAttr(true));
4901+
break;
4902+
}
4903+
case DAK_Transparent: {
4904+
attrs.add(new (context) TransparentAttr(true));
4905+
break;
4906+
}
4907+
case DAK_WarnUnqualifiedAccess: {
4908+
attrs.add(new (context) WarnUnqualifiedAccessAttr(true));
4909+
break;
4910+
}
4911+
default:
4912+
break;
4913+
}
4914+
}
4915+
4916+
return attrs;
4917+
}
4918+
48744919
ValueDecl *cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext) {
48754920
if (auto fn = dyn_cast<FuncDecl>(decl)) {
48764921
// TODO: function templates are specialized during type checking so to
@@ -4882,11 +4927,14 @@ ValueDecl *cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext) {
48824927
isa<clang::FunctionTemplateDecl>(fn->getClangDecl())))
48834928
return nullptr;
48844929

4930+
ASTContext &context = decl->getASTContext();
48854931
auto out = FuncDecl::createImplicit(
4886-
fn->getASTContext(), fn->getStaticSpelling(), fn->getName(),
4932+
context, fn->getStaticSpelling(), fn->getName(),
48874933
fn->getNameLoc(), fn->hasAsync(), fn->hasThrows(),
48884934
fn->getGenericParams(), fn->getParameters(),
48894935
fn->getResultInterfaceType(), newContext);
4936+
auto inheritedAttributes = cloneImportedAttributes(decl, context);
4937+
out->getAttrs().add(inheritedAttributes);
48904938
out->copyFormalAccessFrom(fn);
48914939
out->setBodySynthesizer(synthesizeBaseClassMethodBody, fn);
48924940
out->setSelfAccessKind(fn->getSelfAccessKind());

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ struct Base {
3333
}
3434

3535
static const char *staticInBase() { return "Base::staticInBase"; }
36+
37+
int renamed(int i) __attribute__((swift_name("swiftRenamed(input:)"))) {
38+
return i * 2;
39+
}
40+
41+
void pure() const __attribute__((pure)) {}
3642
};
3743

3844
struct OtherBase {
Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,94 @@
1-
// RUN: %target-swift-ide-test -print-module -module-to-print=Functions -I %S/Inputs -source-filename=x -enable-experimental-cxx-interop | %FileCheck %s
1+
// RUN: %target-swift-ide-test -print-module -print-implicit-attrs -module-to-print=Functions -I %S/Inputs -source-filename=x -enable-experimental-cxx-interop | %FileCheck %s
22

33
// CHECK: struct NonTrivial {
44
// CHECK-NEXT: init()
5+
// CHECK-NEXT: @discardableResult
56
// CHECK-NEXT: func inNonTrivial() -> UnsafePointer<CChar>!
7+
// CHECK-NEXT: @discardableResult
68
// CHECK-NEXT: func inNonTrivialWithArgs(_ a: Int32, _ b: Int32) -> UnsafePointer<CChar>!
79
// CHECK-NEXT: }
810

911
// CHECK-NEXT: struct Base {
1012
// CHECK-NEXT: init()
13+
// CHECK-NEXT: @discardableResult
1114
// CHECK-NEXT: mutating func mutatingInBase() -> UnsafePointer<CChar>!
15+
// CHECK-NEXT: @discardableResult
1216
// CHECK-NEXT: func constInBase() -> UnsafePointer<CChar>!
17+
// CHECK-NEXT: @discardableResult
1318
// CHECK-NEXT: func takesArgsInBase(_ a: Int32, _ b: Int32, _ c: Int32) -> UnsafePointer<CChar>!
19+
// CHECK-NEXT: @discardableResult
1420
// CHECK-NEXT: func takesNonTrivialInBase(_ a: NonTrivial) -> UnsafePointer<CChar>!
21+
// CHECK-NEXT: @discardableResult
1522
// CHECK-NEXT: func returnsNonTrivialInBase() -> NonTrivial
23+
// CHECK-NEXT: @discardableResult
1624
// CHECK-NEXT: func templateInBase<T>(_ t: T) -> UnsafePointer<CChar>!
25+
// CHECK-NEXT: @discardableResult
1726
// CHECK-NEXT: static func staticInBase() -> UnsafePointer<CChar>!
27+
// CHECK-NEXT: @discardableResult
28+
// CHECK-NEXT: mutating func swiftRenamed(input i: Int32) -> Int32
29+
// CHECK-NEXT: @available(swift, obsoleted: 3, renamed: "swiftRenamed(input:)")
30+
// CHECK-NEXT: mutating func renamed(_ i: Int32) -> Int32
31+
// CHECK-NEXT: @_effects(readonly) func pure()
1832
// CHECK-NEXT: }
1933

2034
// CHECK-NEXT: struct OtherBase {
2135
// CHECK-NEXT: init()
36+
// CHECK-NEXT: @discardableResult
2237
// CHECK-NEXT: func inOtherBase() -> UnsafePointer<CChar>!
2338
// CHECK-NEXT: }
2439

2540
// CHECK-NEXT: struct Derived {
2641
// CHECK-NEXT: init()
42+
// CHECK-NEXT: @discardableResult
2743
// CHECK-NEXT: func inDerived() -> UnsafePointer<CChar>!
44+
// CHECK-NEXT: @discardableResult
2845
// CHECK-NEXT: mutating func mutatingInBase() -> UnsafePointer<CChar>?
46+
// CHECK-NEXT: @discardableResult
2947
// CHECK-NEXT: func constInBase() -> UnsafePointer<CChar>?
48+
// CHECK-NEXT: @discardableResult
3049
// CHECK-NEXT: func takesArgsInBase(_ a: Int32, _ b: Int32, _ c: Int32) -> UnsafePointer<CChar>?
50+
// CHECK-NEXT: @discardableResult
3151
// CHECK-NEXT: func takesNonTrivialInBase(_ a: NonTrivial) -> UnsafePointer<CChar>?
52+
// CHECK-NEXT: @discardableResult
3253
// CHECK-NEXT: func returnsNonTrivialInBase() -> NonTrivial
54+
// CHECK-NEXT: @discardableResult
55+
// CHECK-NEXT: mutating func swiftRenamed(input i: Int32) -> Int32
56+
// CHECK-NEXT: @available(swift, obsoleted: 3, renamed: "swiftRenamed(input:)")
57+
// CHECK-NEXT: mutating func renamed(_ i: Int32) -> Int32
58+
// CHECK-NEXT: @_effects(readonly) func pure()
59+
// CHECK-NEXT: @discardableResult
3360
// CHECK-NEXT: func inOtherBase() -> UnsafePointer<CChar>?
3461
// CHECK-NEXT: }
3562

3663
// CHECK-NEXT: struct DerivedFromDerived {
3764
// CHECK-NEXT: init()
65+
// CHECK-NEXT: @discardableResult
3866
// CHECK-NEXT: func topLevel() -> UnsafePointer<CChar>!
67+
// CHECK-NEXT: @discardableResult
3968
// CHECK-NEXT: func inDerived() -> UnsafePointer<CChar>?
69+
// CHECK-NEXT: @discardableResult
4070
// CHECK-NEXT: mutating func mutatingInBase() -> UnsafePointer<CChar>?
71+
// CHECK-NEXT: @discardableResult
4172
// CHECK-NEXT: func constInBase() -> UnsafePointer<CChar>?
73+
// CHECK-NEXT: @discardableResult
4274
// CHECK-NEXT: func takesArgsInBase(_ a: Int32, _ b: Int32, _ c: Int32) -> UnsafePointer<CChar>?
75+
// CHECK-NEXT: @discardableResult
4376
// CHECK-NEXT: func takesNonTrivialInBase(_ a: NonTrivial) -> UnsafePointer<CChar>?
77+
// CHECK-NEXT: @discardableResult
4478
// CHECK-NEXT: func returnsNonTrivialInBase() -> NonTrivial
79+
// CHECK-NEXT: @discardableResult
80+
// CHECK-NEXT: mutating func swiftRenamed(input i: Int32) -> Int32
81+
// CHECK-NEXT: @available(swift, obsoleted: 3, renamed: "swiftRenamed(input:)")
82+
// CHECK-NEXT: mutating func renamed(_ i: Int32) -> Int32
83+
// CHECK-NEXT: @_effects(readonly) func pure()
84+
// CHECK-NEXT: @discardableResult
4585
// CHECK-NEXT: func inOtherBase() -> UnsafePointer<CChar>?
4686
// CHECK-NEXT: }
4787

4888
// CHECK-NEXT: struct DerivedFromNonTrivial {
4989
// CHECK-NEXT: init()
90+
// CHECK-NEXT: @discardableResult
5091
// CHECK-NEXT: func inNonTrivial() -> UnsafePointer<CChar>?
92+
// CHECK-NEXT: @discardableResult
5193
// CHECK-NEXT: func inNonTrivialWithArgs(_ a: Int32, _ b: Int32) -> UnsafePointer<CChar>?
5294
// CHECK-NEXT: }

0 commit comments

Comments
 (0)