Skip to content

[Compatibility50] Look up swift_getObjCClassMetadata at runtime. #27170

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion stdlib/toolchain/Compatibility50/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "Overrides.h"
#include "../../public/runtime/Private.h"
#include "swift/Basic/Lazy.h"
#include <dlfcn.h>
#include <mach-o/dyld.h>
#include <mach-o/getsect.h>
#include <objc/runtime.h>
Expand Down Expand Up @@ -89,13 +90,25 @@ static void registerAddImageCallback(void *) {
_dyld_register_func_for_add_image(addImageCallback);
}

static const Metadata *getObjCClassMetadata(const ClassMetadata *c) {
// Look up swift_getObjCClassMetadata dynamically. This handles the case
// where the main executable can't link against libswiftCore.dylib because
// it will be loaded dynamically from a location that isn't known at build
// time.
using FPtr = const Metadata *(*)(const ClassMetadata *);
FPtr func = SWIFT_LAZY_CONSTANT(
reinterpret_cast<FPtr>(dlsym(RTLD_DEFAULT, "swift_getObjCClassMetadata")));

return func(c);
}

// Clone of private helper swift::_swiftoverride_class_getSuperclass
// for use in the override implementation.
static const Metadata *_swift50override_class_getSuperclass(
const Metadata *theClass) {
if (const ClassMetadata *classType = theClass->getClassObject()) {
if (classHasSuperclass(classType))
return getMetadataForClass(classType->Superclass);
return getObjCClassMetadata(classType->Superclass);
}

if (const ForeignClassMetadata *foreignClassType
Expand Down
4 changes: 2 additions & 2 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ foreach(SDK ${SWIFT_SDKS})

# NOTE create a stub BlocksRuntime library that can be used for the
# reflection tests
file(WRITE ${test_bin_dir}/BlocksRuntime.c
file(WRITE ${test_bin_dir}/Inputs/BlocksRuntime.c
"void
#if defined(_WIN32)
__declspec(dllexport)
Expand All @@ -220,7 +220,7 @@ _Block_release(void) { }\n")
ARCHITECTURE ${ARCH}
SDK ${SDK}
INSTALL_IN_COMPONENT dev
${test_bin_dir}/BlocksRuntime.c)
${test_bin_dir}/Inputs/BlocksRuntime.c)
set_target_properties(BlocksRuntimeStub${VARIANT_SUFFIX} PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${test_bin_dir}
LIBRARY_OUTPUT_DIRECTORY ${test_bin_dir}
Expand Down
4 changes: 2 additions & 2 deletions test/lit.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@ config.test_format = swift_test.SwiftTest(coverage_mode=config.coverage_mode,
execute_external=not use_lit_shell)

# suffixes: A list of file extensions to treat as test files.
config.suffixes = ['.swift', '.ll', '.sil', '.gyb', '.m', '.swiftinterface',
'.test-sh']
config.suffixes = ['.swift', '.ll', '.sil', '.gyb', '.m', '.c',
'.swiftinterface', '.test-sh']

# excludes: A list of directories to exclude from the testsuite. The 'Inputs'
# subdirectories contain auxiliary inputs for various tests in their parent
Expand Down
13 changes: 13 additions & 0 deletions test/stdlib/Compatibility50Linking.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RUN: %empty-directory(%t)
// RUN: %target-clang %s -all_load %test-resource-dir/%target-sdk-name/libswiftCompatibility50.a -lobjc -o %t/main
// RUN: %target-run %t/main
// REQUIRES: objc_interop
// REQUIRES: executable_test

// The compatibility library needs to have no build-time dependencies on
// libswiftCore so it can be linked into a program that doesn't link
// libswiftCore, but will load it at runtime, such as xctest.
//
// Test this by linking it into a plain C program and making sure it builds.

int main(void) {}