Skip to content

Commit 8651af4

Browse files
committed
Make @objcImpl work with @_cdecl
No real diagnostics yet, but we’re emitting mostly correct code.
1 parent 95eaeaf commit 8651af4

File tree

15 files changed

+130
-58
lines changed

15 files changed

+130
-58
lines changed

include/swift/AST/Attr.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ DECL_ATTR(_restatedObjCConformance, RestatedObjCConformance,
246246
OnProtocol | UserInaccessible | LongAttribute | RejectByParser | NotSerialized | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
247247
70)
248248
DECL_ATTR(_objcImplementation, ObjCImplementation,
249-
OnExtension | UserInaccessible | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,
249+
OnExtension | OnAbstractFunction | UserInaccessible | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,
250250
72)
251251
DECL_ATTR(_optimize, Optimize,
252252
OnAbstractFunction | OnSubscript | OnVar | UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,

include/swift/AST/Decl.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,11 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
941941
/// attribute macro expansion.
942942
DeclAttributes getSemanticAttrs() const;
943943

944+
/// True if this declaration provides an implementation for an imported
945+
/// Objective-C declaration. This implies various restrictions and special
946+
/// behaviors for it and, if it's an extension, its members.
947+
bool isObjCImplementation() const;
948+
944949
using AuxiliaryDeclCallback = llvm::function_ref<void(Decl *)>;
945950

946951
/// Iterate over the auxiliary declarations for this declaration,
@@ -1836,11 +1841,6 @@ class ExtensionDecl final : public GenericContext, public Decl,
18361841
/// resiliently moved into the original protocol itself.
18371842
bool isEquivalentToExtendedContext() const;
18381843

1839-
/// True if this extension provides an implementation for an imported
1840-
/// Objective-C \c \@interface. This implies various restrictions and special
1841-
/// behaviors for its members.
1842-
bool isObjCImplementation() const;
1843-
18441844
/// Returns the name of the category specified by the \c \@_objcImplementation
18451845
/// attribute, or \c None if the name is invalid. Do not call unless
18461846
/// \c isObjCImplementation() returns \c true.

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1743,6 +1743,10 @@ ERROR(attr_objc_implementation_category_not_found,none,
17431743
NOTE(attr_objc_implementation_fixit_remove_category_name,none,
17441744
"remove arguments to implement the main '@interface' for this class",
17451745
())
1746+
ERROR(attr_objc_implementation_no_category_for_func,none,
1747+
"%kind0 does not belong to an Objective-C category; remove the category "
1748+
"name from this attribute",
1749+
(ValueDecl*))
17461750
ERROR(attr_objc_implementation_no_conformance,none,
17471751
"'@_objcImplementation' extension cannot add conformance to %0; "
17481752
"add this conformance %select{with an ordinary extension|"

lib/AST/Decl.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1847,7 +1847,7 @@ Type ExtensionDecl::getExtendedType() const {
18471847
return ErrorType::get(ctx);
18481848
}
18491849

1850-
bool ExtensionDecl::isObjCImplementation() const {
1850+
bool Decl::isObjCImplementation() const {
18511851
return getAttrs().hasAttribute<ObjCImplementationAttr>(/*AllowInvalid=*/true);
18521852
}
18531853

@@ -4404,7 +4404,8 @@ static bool checkAccess(const DeclContext *useDC, const ValueDecl *VD,
44044404
// a context where we would access its storage directly, forbid access. Name
44054405
// lookups will instead find and use the matching interface decl.
44064406
// FIXME: Passing `true` for `isAccessOnSelf` may cause false positives.
4407-
if (isObjCMemberImplementation(VD, getAccessLevel) &&
4407+
if ((VD->isObjCImplementation() ||
4408+
isObjCMemberImplementation(VD, getAccessLevel)) &&
44084409
VD->getAccessSemanticsFromContext(useDC, /*isAccessOnSelf=*/true)
44094410
!= AccessSemantics::DirectToStorage)
44104411
return false;

lib/IRGen/GenDecl.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3544,7 +3544,10 @@ llvm::Function *IRGenModule::getAddrOfSILFunction(
35443544
if (hasOrderNumber) {
35453545
auto &fnList = Module.getFunctionList();
35463546
fnList.remove(fn);
3547-
fnList.insert(llvm::Module::iterator(insertBefore), fn);
3547+
if (insertBefore)
3548+
fnList.insert(llvm::Module::iterator(insertBefore), fn);
3549+
else
3550+
fnList.push_back(fn);
35483551

35493552
EmittedFunctionsByOrder.insert(orderNumber, fn);
35503553
}

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2858,12 +2858,16 @@ static bool hasExposeAttr(const ValueDecl *VD, bool isExtension = false) {
28582858
return false;
28592859
}
28602860

2861-
/// Skip \c \@objcImplementation \c extension member implementations and
2862-
/// overrides. They are already declared in handwritten headers, and they may
2863-
/// have attributes that aren't allowed in a category.
2861+
/// Skip \c \@objcImplementation functions, \c extension member
2862+
/// implementations, and overrides. They are already declared in handwritten
2863+
/// headers, and they may have attributes that aren't allowed in a category.
28642864
///
28652865
/// \return true if \p VD should \em not be included in the header.
28662866
static bool excludeForObjCImplementation(const ValueDecl *VD) {
2867+
// If it's an ObjC implementation (and not an extension, which might have
2868+
// members that need printing), skip it; it's declared elsewhere.
2869+
if (VD->isObjCImplementation() && ! isa<ExtensionDecl>(VD))
2870+
return true;
28672871
// Exclude member implementations; they are declared elsewhere.
28682872
if (VD->isObjCMemberImplementation())
28692873
return true;

lib/Sema/TypeCheckAttr.cpp

Lines changed: 64 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1517,60 +1517,79 @@ void AttributeChecker::visitNonObjCAttr(NonObjCAttr *attr) {
15171517

15181518
void AttributeChecker::
15191519
visitObjCImplementationAttr(ObjCImplementationAttr *attr) {
1520-
auto ED = cast<ExtensionDecl>(D);
1521-
if (ED->isConstrainedExtension())
1522-
diagnoseAndRemoveAttr(attr,
1523-
diag::attr_objc_implementation_must_be_unconditional);
1520+
if (auto ED = dyn_cast<ExtensionDecl>(D)) {
1521+
if (ED->isConstrainedExtension())
1522+
diagnoseAndRemoveAttr(attr,
1523+
diag::attr_objc_implementation_must_be_unconditional);
15241524

1525-
auto CD = dyn_cast<ClassDecl>(ED->getExtendedNominal());
1526-
if (!CD) {
1527-
diagnoseAndRemoveAttr(attr,
1528-
diag::attr_objc_implementation_must_extend_class,
1529-
ED->getExtendedNominal());
1530-
ED->getExtendedNominal()->diagnose(diag::decl_declared_here,
1531-
ED->getExtendedNominal());
1532-
return;
1533-
}
1525+
auto CD = dyn_cast<ClassDecl>(ED->getExtendedNominal());
1526+
if (!CD) {
1527+
diagnoseAndRemoveAttr(attr,
1528+
diag::attr_objc_implementation_must_extend_class,
1529+
ED->getExtendedNominal());
1530+
ED->getExtendedNominal()->diagnose(diag::decl_declared_here,
1531+
ED->getExtendedNominal());
1532+
return;
1533+
}
15341534

1535-
if (!CD->hasClangNode()) {
1536-
diagnoseAndRemoveAttr(attr, diag::attr_objc_implementation_must_be_imported,
1537-
CD);
1538-
CD->diagnose(diag::decl_declared_here, CD);
1539-
return;
1540-
}
1535+
if (!CD->hasClangNode()) {
1536+
diagnoseAndRemoveAttr(attr, diag::attr_objc_implementation_must_be_imported,
1537+
CD);
1538+
CD->diagnose(diag::decl_declared_here, CD);
1539+
return;
1540+
}
15411541

1542-
if (!CD->hasSuperclass()) {
1543-
diagnoseAndRemoveAttr(attr, diag::attr_objc_implementation_must_have_super,
1544-
CD);
1545-
CD->diagnose(diag::decl_declared_here, CD);
1546-
return;
1547-
}
1542+
if (!CD->hasSuperclass()) {
1543+
diagnoseAndRemoveAttr(attr, diag::attr_objc_implementation_must_have_super,
1544+
CD);
1545+
CD->diagnose(diag::decl_declared_here, CD);
1546+
return;
1547+
}
15481548

1549-
if (CD->isTypeErasedGenericClass()) {
1550-
diagnoseAndRemoveAttr(attr, diag::objc_implementation_cannot_have_generics,
1551-
CD);
1552-
CD->diagnose(diag::decl_declared_here, CD);
1553-
}
1549+
if (CD->isTypeErasedGenericClass()) {
1550+
diagnoseAndRemoveAttr(attr, diag::objc_implementation_cannot_have_generics,
1551+
CD);
1552+
CD->diagnose(diag::decl_declared_here, CD);
1553+
}
15541554

1555-
if (!attr->isCategoryNameInvalid() && !ED->getImplementedObjCDecl()) {
1556-
diagnose(attr->getLocation(),
1557-
diag::attr_objc_implementation_category_not_found,
1558-
attr->CategoryName, CD);
1559-
1560-
// attr->getRange() covers the attr name and argument list; adjust it to
1561-
// exclude the first token.
1562-
auto newStart = Lexer::getLocForEndOfToken(Ctx.SourceMgr,
1563-
attr->getRange().Start);
1564-
if (attr->getRange().contains(newStart)) {
1565-
auto argListRange = SourceRange(newStart, attr->getRange().End);
1555+
if (!attr->isCategoryNameInvalid() && !ED->getImplementedObjCDecl()) {
15661556
diagnose(attr->getLocation(),
1567-
diag::attr_objc_implementation_fixit_remove_category_name)
1568-
.fixItRemove(argListRange);
1557+
diag::attr_objc_implementation_category_not_found,
1558+
attr->CategoryName, CD);
1559+
1560+
// attr->getRange() covers the attr name and argument list; adjust it to
1561+
// exclude the first token.
1562+
auto newStart = Lexer::getLocForEndOfToken(Ctx.SourceMgr,
1563+
attr->getRange().Start);
1564+
if (attr->getRange().contains(newStart)) {
1565+
auto argListRange = SourceRange(newStart, attr->getRange().End);
1566+
diagnose(attr->getLocation(),
1567+
diag::attr_objc_implementation_fixit_remove_category_name)
1568+
.fixItRemove(argListRange);
1569+
}
1570+
1571+
attr->setCategoryNameInvalid();
1572+
1573+
return;
15691574
}
1575+
}
1576+
else if (auto AFD = dyn_cast<AbstractFunctionDecl>(D)) {
1577+
if (!attr->CategoryName.empty()) {
1578+
auto diagnostic =
1579+
diagnose(attr->getLocation(),
1580+
diag::attr_objc_implementation_no_category_for_func, AFD);
15701581

1571-
attr->setCategoryNameInvalid();
1582+
// attr->getRange() covers the attr name and argument list; adjust it to
1583+
// exclude the first token.
1584+
auto newStart = Lexer::getLocForEndOfToken(Ctx.SourceMgr,
1585+
attr->getRange().Start);
1586+
if (attr->getRange().contains(newStart)) {
1587+
auto argListRange = SourceRange(newStart, attr->getRange().End);
1588+
diagnostic.fixItRemove(argListRange);
1589+
}
15721590

1573-
return;
1591+
attr->setCategoryNameInvalid();
1592+
}
15741593
}
15751594
}
15761595

test/IRGen/Inputs/objc_implementation.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
@end
2626

27+
extern void implFunc(int param);
28+
2729

2830
@interface NoImplClass
2931

test/IRGen/objc_implementation.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,13 @@ open class SwiftSubclass: ImplClass {
139139
// Functions
140140
//
141141

142+
@_objcImplementation @_cdecl("implFunc")
143+
public func implFunc(_ param: Int32) {}
144+
142145
public func fn(impl: ImplClass, swiftSub: SwiftSubclass) {
143146
impl.mainMethod(0)
144147
swiftSub.mainMethod(1)
148+
implFunc(2)
145149
}
146150

147151
// Swift calling convention -[ImplClass init]
@@ -239,12 +243,18 @@ public func fn(impl: ImplClass, swiftSub: SwiftSubclass) {
239243
// Swift calling convention SwiftSubclass.deinit (deallocating)
240244
// CHECK-LABEL: define swiftcc void @"$s19objc_implementation13SwiftSubclassCfD"
241245

246+
// inplFunc(_:)
247+
// CHECK-LABEL: define void @implFunc
248+
// FIXME: We'd like this to be internal or hidden, not public.
249+
// CHECK: define swiftcc void @"$s19objc_implementation8implFuncyys5Int32VF"
250+
242251
// fn(impl:swiftSub:)
243252
// CHECK-LABEL: define swiftcc void @"$s19objc_implementation2fn4impl8swiftSubySo9ImplClassC_AA13SwiftSubclassCtF"
244253
// CHECK: [[SEL_1:%[^ ]+]] = load ptr, ptr @"\01L_selector(mainMethod:)", align 8
245254
// CHECK: call void @objc_msgSend(ptr {{.*}}, ptr [[SEL_1]], i32 0)
246255
// CHECK: [[SEL_2:%[^ ]+]] = load ptr, ptr @"\01L_selector(mainMethod:)", align 8
247256
// CHECK: call void @objc_msgSend(ptr {{.*}}, ptr [[SEL_2]], i32 1)
257+
// CHECK: call void @implFunc
248258
// CHECK: ret void
249259
// CHECK: }
250260

test/Interpreter/Inputs/objc_implementation.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@ NS_ASSUME_NONNULL_BEGIN
1414

1515
@end
1616

17+
extern void implFunc(int param);
18+
1719
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)