Skip to content

Commit e35f077

Browse files
authored
Merge pull request swiftlang#33349 from ellishg/master
[IRGen] Call objc_direct methods correctly
2 parents 540455a + 3aa081c commit e35f077

File tree

17 files changed

+387
-36
lines changed

17 files changed

+387
-36
lines changed

lib/AST/NameLookup.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
//
1515
//===----------------------------------------------------------------------===//
1616

17+
#include "clang/AST/DeclObjC.h"
1718
#include "swift/AST/NameLookup.h"
1819
#include "swift/AST/ASTContext.h"
1920
#include "swift/AST/ASTVisitor.h"
@@ -1837,6 +1838,17 @@ AnyObjectLookupRequest::evaluate(Evaluator &evaluator, const DeclContext *dc,
18371838
if (!decl->isObjC())
18381839
continue;
18391840

1841+
// If the declaration is objc_direct, it cannot be called dynamically.
1842+
if (auto clangDecl = decl->getClangDecl()) {
1843+
if (auto objCMethod = dyn_cast<clang::ObjCMethodDecl>(clangDecl)) {
1844+
if (objCMethod->isDirectMethod())
1845+
continue;
1846+
} else if (auto objCProperty = dyn_cast<clang::ObjCPropertyDecl>(clangDecl)) {
1847+
if (objCProperty->isDirectProperty())
1848+
continue;
1849+
}
1850+
}
1851+
18401852
// If the declaration has an override, name lookup will also have
18411853
// found the overridden method. Skip this declaration, because we
18421854
// prefer the overridden method.
@@ -1848,7 +1860,6 @@ AnyObjectLookupRequest::evaluate(Evaluator &evaluator, const DeclContext *dc,
18481860

18491861
// If we didn't see this declaration before, and it's an acceptable
18501862
// result, add it to the list.
1851-
// declaration to the list.
18521863
if (knownDecls.insert(decl).second &&
18531864
isAcceptableLookupResult(dc, options, decl,
18541865
/*onlyCompleteObjectInits=*/false))

lib/ClangImporter/ImportDecl.cpp

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4579,7 +4579,8 @@ namespace {
45794579
/*genericParams=*/nullptr, bodyParams,
45804580
resultTy, async, throws, dc, decl);
45814581

4582-
result->setAccess(getOverridableAccessLevel(dc));
4582+
result->setAccess(decl->isDirectMethod() ? AccessLevel::Public
4583+
: getOverridableAccessLevel(dc));
45834584

45844585
// Optional methods in protocols.
45854586
if (decl->getImplementationControl() == clang::ObjCMethodDecl::Optional &&
@@ -5331,8 +5332,9 @@ namespace {
53315332
}
53325333

53335334
auto type = importedType.getType();
5334-
auto result = Impl.createDeclWithClangNode<VarDecl>(decl,
5335-
getOverridableAccessLevel(dc),
5335+
const auto access = decl->isDirectProperty() ? AccessLevel::Public
5336+
: getOverridableAccessLevel(dc);
5337+
auto result = Impl.createDeclWithClangNode<VarDecl>(decl, access,
53365338
/*IsStatic*/decl->isClassProperty(), VarDecl::Introducer::Var,
53375339
Impl.importSourceLoc(decl->getLocation()), name, dc);
53385340
result->setInterfaceType(type);
@@ -7023,7 +7025,13 @@ SwiftDeclConverter::importSubscript(Decl *decl,
70237025
bodyParams, decl->getLoc(),
70247026
elementTy, dc,
70257027
getter->getClangNode());
7026-
const auto access = getOverridableAccessLevel(dc);
7028+
7029+
bool IsObjCDirect = false;
7030+
if (auto objCDecl = dyn_cast<clang::ObjCMethodDecl>(getter->getClangDecl())) {
7031+
IsObjCDirect = objCDecl->isDirectMethod();
7032+
}
7033+
const auto access = IsObjCDirect ? AccessLevel::Public
7034+
: getOverridableAccessLevel(dc);
70277035
subscript->setAccess(access);
70287036
subscript->setSetterAccess(access);
70297037

@@ -7877,10 +7885,13 @@ void ClangImporter::Implementation::importAttributes(
78777885

78787886
if (auto method = dyn_cast<clang::ObjCMethodDecl>(ClangDecl)) {
78797887
if (method->isDirectMethod() && !AnyUnavailable) {
7880-
auto attr = AvailableAttr::createPlatformAgnostic(
7881-
C, "", "", PlatformAgnosticAvailabilityKind::UnavailableInSwift);
7882-
MappedDecl->getAttrs().add(attr);
7883-
AnyUnavailable = true;
7888+
assert(isa<AbstractFunctionDecl>(MappedDecl) &&
7889+
"objc_direct declarations are expected to be an AbstractFunctionDecl");
7890+
MappedDecl->getAttrs().add(new (C) FinalAttr(/*IsImplicit=*/true));
7891+
if (auto accessorDecl = dyn_cast<AccessorDecl>(MappedDecl)) {
7892+
auto attr = new (C) FinalAttr(/*isImplicit=*/true);
7893+
accessorDecl->getStorage()->getAttrs().add(attr);
7894+
}
78847895
}
78857896
}
78867897

lib/IRGen/GenDecl.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2860,12 +2860,18 @@ llvm::Function *IRGenModule::getAddrOfSILFunction(
28602860
// the insert-before point.
28612861
llvm::Constant *clangAddr = nullptr;
28622862
if (auto clangDecl = f->getClangDecl()) {
2863-
auto globalDecl = getClangGlobalDeclForFunction(clangDecl);
2864-
clangAddr = getAddrOfClangGlobalDecl(globalDecl, forDefinition);
2863+
// If we have an Objective-C Clang declaration, it must be a direct
2864+
// method and we want to generate the IR declaration ourselves.
2865+
if (auto objcDecl = dyn_cast<clang::ObjCMethodDecl>(clangDecl)) {
2866+
assert(objcDecl->isDirectMethod());
2867+
} else {
2868+
auto globalDecl = getClangGlobalDeclForFunction(clangDecl);
2869+
clangAddr = getAddrOfClangGlobalDecl(globalDecl, forDefinition);
28652870

2866-
if (auto ctor = dyn_cast<clang::CXXConstructorDecl>(clangDecl)) {
2867-
clangAddr =
2868-
emitCXXConstructorThunkIfNeeded(*this, f, ctor, entity, clangAddr);
2871+
if (auto ctor = dyn_cast<clang::CXXConstructorDecl>(clangDecl)) {
2872+
clangAddr =
2873+
emitCXXConstructorThunkIfNeeded(*this, f, ctor, entity, clangAddr);
2874+
}
28692875
}
28702876
}
28712877

lib/IRGen/GenObjC.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,14 @@ Callee irgen::getObjCMethodCallee(IRGenFunction &IGF,
661661
return Callee(std::move(info), fn, receiverValue, selectorValue);
662662
}
663663

664+
Callee irgen::getObjCDirectMethodCallee(CalleeInfo &&info, const FunctionPointer &fn,
665+
llvm::Value *selfValue) {
666+
// Direct calls to Objective-C methods have a selector value of `undef`.
667+
auto selectorType = fn.getFunctionType()->getParamType(1);
668+
auto selectorValue = llvm::UndefValue::get(selectorType);
669+
return Callee(std::move(info), fn, selfValue, selectorValue);
670+
}
671+
664672
/// Call [self allocWithZone: nil].
665673
llvm::Value *irgen::emitObjCAllocObjectCall(IRGenFunction &IGF,
666674
llvm::Value *self,

lib/IRGen/GenObjC.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ namespace irgen {
8888
Callee getObjCMethodCallee(IRGenFunction &IGF, const ObjCMethod &method,
8989
llvm::Value *selfValue, CalleeInfo &&info);
9090

91+
/// Prepare a callee for an Objective-C method with the `objc_direct` attribute.
92+
Callee getObjCDirectMethodCallee(CalleeInfo &&info, const FunctionPointer &fn,
93+
llvm::Value *selfValue);
94+
9195
/// Emit a partial application of an Objective-C method to its 'self'
9296
/// argument.
9397
void emitObjCPartialApplication(IRGenFunction &IGF,

lib/IRGen/IRGenSIL.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2573,6 +2573,10 @@ Callee LoweredValue::getCallee(IRGenFunction &IGF,
25732573
switch (kind) {
25742574
case Kind::FunctionPointer: {
25752575
auto &fn = getFunctionPointer();
2576+
if (calleeInfo.OrigFnType->getRepresentation() ==
2577+
SILFunctionTypeRepresentation::ObjCMethod) {
2578+
return getObjCDirectMethodCallee(std::move(calleeInfo), fn, selfValue);
2579+
}
25762580
return Callee(std::move(calleeInfo), fn, selfValue);
25772581
}
25782582

lib/SIL/IR/SILDeclRef.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/SIL/SILLinkage.h"
2222
#include "swift/SIL/SILLocation.h"
2323
#include "swift/SILOptimizer/Utils/SpecializationMangler.h"
24+
#include "clang/AST/ASTContext.h"
2425
#include "clang/AST/Attr.h"
2526
#include "clang/AST/Decl.h"
2627
#include "clang/AST/DeclCXX.h"
@@ -717,6 +718,16 @@ std::string SILDeclRef::mangle(ManglingKind MKind) const {
717718
return SS.str();
718719
}
719720
return namedClangDecl->getName().str();
721+
} else if (auto objcDecl = dyn_cast<clang::ObjCMethodDecl>(clangDecl)) {
722+
if (objcDecl->isDirectMethod()) {
723+
std::string storage;
724+
llvm::raw_string_ostream SS(storage);
725+
clang::ASTContext &ctx = clangDecl->getASTContext();
726+
std::unique_ptr<clang::MangleContext> mangler(ctx.createMangleContext());
727+
mangler->mangleObjCMethodName(objcDecl, SS, /*includePrefixByte=*/true,
728+
/*includeCategoryNamespace=*/false);
729+
return SS.str();
730+
}
720731
}
721732
}
722733
}

lib/SILGen/SILGenApply.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "swift/SIL/SILArgument.h"
4141
#include "clang/AST/DeclCXX.h"
4242
#include "llvm/Support/Compiler.h"
43+
#include "clang/AST/DeclObjC.h"
4344

4445
using namespace swift;
4546
using namespace Lowering;
@@ -1063,7 +1064,18 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
10631064
auto constant = SILDeclRef(afd).asForeign(requiresForeignEntryPoint(afd));
10641065

10651066
auto subs = e->getDeclRef().getSubstitutions();
1066-
setCallee(Callee::forClassMethod(SGF, constant, subs, e));
1067+
1068+
bool isObjCDirect = false;
1069+
if (auto objcDecl = dyn_cast_or_null<clang::ObjCMethodDecl>(
1070+
afd->getClangDecl())) {
1071+
isObjCDirect = objcDecl->isDirectMethod();
1072+
}
1073+
1074+
if (isObjCDirect) {
1075+
setCallee(Callee::forDirect(SGF, constant, subs, e));
1076+
} else {
1077+
setCallee(Callee::forClassMethod(SGF, constant, subs, e));
1078+
}
10671079
}
10681080

10691081
//
@@ -5134,8 +5146,14 @@ static Callee getBaseAccessorFunctionRef(SILGenFunction &SGF,
51345146
}
51355147
}
51365148

5149+
bool isObjCDirect = false;
5150+
if (auto objcDecl = dyn_cast_or_null<clang::ObjCMethodDecl>(
5151+
decl->getClangDecl())) {
5152+
isObjCDirect = objcDecl->isDirectMethod();
5153+
}
5154+
51375155
// Dispatch in a struct/enum or to a final method is always direct.
5138-
if (!isClassDispatch)
5156+
if (!isClassDispatch || isObjCDirect)
51395157
return Callee::forDirect(SGF, constant, subs, loc);
51405158

51415159
// Otherwise, if we have a non-final class dispatch to a normal method,

lib/Sema/LookupVisibleDecls.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
//===----------------------------------------------------------------------===//
1717

1818
#include "TypeChecker.h"
19+
#include "clang/AST/DeclObjC.h"
1920
#include "swift/AST/ASTContext.h"
2021
#include "swift/AST/GenericSignature.h"
2122
#include "swift/AST/GenericSignatureBuilder.h"
@@ -314,6 +315,17 @@ static void doDynamicLookup(VisibleDeclConsumer &Consumer,
314315
if (!D->isObjC())
315316
return;
316317

318+
// If the declaration is objc_direct, it cannot be called dynamically.
319+
if (auto clangDecl = D->getClangDecl()) {
320+
if (auto objCMethod = dyn_cast<clang::ObjCMethodDecl>(clangDecl)) {
321+
if (objCMethod->isDirectMethod())
322+
return;
323+
} else if (auto objCProperty = dyn_cast<clang::ObjCPropertyDecl>(clangDecl)) {
324+
if (objCProperty->isDirectProperty())
325+
return;
326+
}
327+
}
328+
317329
if (D->isRecursiveValidation())
318330
return;
319331

test/ClangImporter/Inputs/objc_direct.h

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)