Skip to content

Commit e755814

Browse files
committed
IRGen: Use extern_weak linkage for Clang symbols from @_weakLinked imported modules.
rdar://96098097
1 parent 03cf699 commit e755814

File tree

7 files changed

+76
-12
lines changed

7 files changed

+76
-12
lines changed

include/swift/AST/Module.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -414,12 +414,11 @@ class ModuleDecl
414414
/// present overlays as if they were part of their underlying module.
415415
std::pair<ModuleDecl *, Identifier> getDeclaringModuleAndBystander();
416416

417+
public:
417418
/// If this is a traditional (non-cross-import) overlay, get its underlying
418419
/// module if one exists.
419420
ModuleDecl *getUnderlyingModuleIfOverlay() const;
420421

421-
public:
422-
423422
/// Returns true if this module is an underscored cross import overlay
424423
/// declared by \p other or its underlying clang module, either directly or
425424
/// transitively (via intermediate cross-import overlays - for cross-imports
@@ -686,8 +685,9 @@ class ModuleDecl
686685
// Is \p spiGroup accessible as an explicitly imported SPI from this module?
687686
bool isImportedAsSPI(Identifier spiGroup, const ModuleDecl *fromModule) const;
688687

689-
/// Is \p importedModule imported as \c @_weakLinked from this module?
690-
bool importsModuleAsWeakLinked(const ModuleDecl *importedModule) const;
688+
/// Is \p targetDecl from a module that is imported as \c @_weakLinked from
689+
/// this module?
690+
bool isImportedAsWeakLinked(const Decl *targetDecl) const;
691691

692692
/// \sa getImportedModules
693693
enum class ImportFilterKind {

lib/AST/Decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1002,7 +1002,7 @@ bool Decl::isWeakImported(ModuleDecl *fromModule) const {
10021002
if (isAlwaysWeakImported())
10031003
return true;
10041004

1005-
if (fromModule->importsModuleAsWeakLinked(getModuleContext()))
1005+
if (fromModule->isImportedAsWeakLinked(this))
10061006
return true;
10071007

10081008
auto availability = getAvailabilityForLinkage();

lib/AST/Module.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2576,8 +2576,18 @@ bool SourceFile::isImportedAsSPI(const ValueDecl *targetDecl) const {
25762576

25772577
bool SourceFile::importsModuleAsWeakLinked(const ModuleDecl *module) const {
25782578
for (auto &import : *Imports) {
2579-
if (import.options.contains(ImportFlags::WeakLinked) &&
2580-
module == import.module.importedModule)
2579+
if (!import.options.contains(ImportFlags::WeakLinked))
2580+
continue;
2581+
2582+
const ModuleDecl *importedModule = import.module.importedModule;
2583+
if (module == importedModule)
2584+
return true;
2585+
2586+
// Also check whether the target module is actually the underlyingClang
2587+
// module for this @_weakLinked import.
2588+
const ModuleDecl *clangModule =
2589+
importedModule->getUnderlyingModuleIfOverlay();
2590+
if (module == clangModule)
25812591
return true;
25822592
}
25832593
return false;
@@ -2608,10 +2618,10 @@ bool ModuleDecl::isImportedAsSPI(Identifier spiGroup,
26082618
return importedSPIGroups.count(spiGroup);
26092619
}
26102620

2611-
bool ModuleDecl::importsModuleAsWeakLinked(
2612-
const ModuleDecl *importedModule) const {
2621+
bool ModuleDecl::isImportedAsWeakLinked(const Decl *targetDecl) const {
2622+
const auto *declaringModule = targetDecl->getModuleContext();
26132623
for (auto file : getFiles()) {
2614-
if (file->importsModuleAsWeakLinked(importedModule))
2624+
if (file->importsModuleAsWeakLinked(declaringModule))
26152625
return true;
26162626
}
26172627
return false;

lib/IRGen/GenDecl.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2491,6 +2491,16 @@ Address IRGenModule::getAddrOfSILGlobalVariable(SILGlobalVariable *var,
24912491
auto addr = getAddrOfClangGlobalDecl(cast<clang::VarDecl>(clangDecl),
24922492
forDefinition);
24932493

2494+
// Override the linkage computed by Clang if the decl is from another
2495+
// module that imported @_weakLinked.
2496+
//
2497+
// FIXME: We should be able to set the linkage unconditionally here but
2498+
// some fixes are needed for Cxx interop.
2499+
if (auto globalVar = dyn_cast<llvm::GlobalVariable>(addr)) {
2500+
if (getSwiftModule()->isImportedAsWeakLinked(var->getDecl()))
2501+
globalVar->setLinkage(link.getLinkage());
2502+
}
2503+
24942504
// If we're not emitting this to define it, make sure we cast it to the
24952505
// right type.
24962506
if (!forDefinition) {
@@ -3242,8 +3252,16 @@ llvm::Function *IRGenModule::getAddrOfSILFunction(
32423252
if (clangAddr) {
32433253
fn = dyn_cast<llvm::Function>(clangAddr->stripPointerCasts());
32443254

3245-
// If we have a function, move it to the appropriate position.
32463255
if (fn) {
3256+
// Override the linkage computed by Clang if the decl is from another
3257+
// module that imported @_weakLinked.
3258+
//
3259+
// FIXME: We should be able to set the linkage unconditionally here but
3260+
// some fixes are needed for Cxx interop.
3261+
if (!forDefinition && f->isWeakImportedByModule())
3262+
fn->setLinkage(link.getLinkage());
3263+
3264+
// If we have a function, move it to the appropriate position.
32473265
if (hasOrderNumber) {
32483266
auto &fnList = Module.getFunctionList();
32493267
fnList.remove(fn);

lib/SIL/IR/SILFunction.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,9 @@ bool SILFunction::isTypeABIAccessible(SILType type) const {
453453
}
454454

455455
bool SILFunction::isWeakImported() const {
456+
if (isWeakImportedByModule())
457+
return true;
458+
456459
// For imported functions check the Clang declaration.
457460
if (ClangNodeOwner)
458461
return ClangNodeOwner->getClangDecl()->isWeakImported();
@@ -462,7 +465,7 @@ bool SILFunction::isWeakImported() const {
462465
if (!isAvailableExternally())
463466
return false;
464467

465-
if (isAlwaysWeakImported() || isWeakImportedByModule())
468+
if (isAlwaysWeakImported())
466469
return true;
467470

468471
if (Availability.isAlwaysAvailable())

test/IRGen/Inputs/usr/include/BridgeTestFoundation.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,13 @@ __attribute__((availability(macosx,introduced=10.51)))
5353
@interface NSUserNotificationAction : NSObject
5454
@end
5555

56+
void always_available_function();
57+
5658
__attribute__((availability(macosx,introduced=10.51)))
5759
void future_function_should_be_weak();
5860

5961
extern int weak_variable __attribute__((weak_import));
62+
extern int strong_variable;
6063

6164
@interface NSError : NSObject
6265

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %build-irgen-test-overlays
3+
4+
// RUN: %target-swift-frontend(mock-sdk: -target %target-cpu-apple-macosx10.50 -sdk %S/Inputs -I %t) -primary-file %s -emit-ir | %FileCheck %s
5+
6+
// REQUIRES: objc_interop
7+
8+
@_weakLinked import Foundation
9+
10+
func testObjCClass() {
11+
// CHECK-DAG: @"OBJC_CLASS_$_NSNotification" = extern_weak global %objc_class
12+
_ = NSNotification()
13+
}
14+
15+
func testGlobalVariables() {
16+
// CHECK-DAG: @weak_variable = extern_weak global
17+
_ = weak_variable
18+
19+
// CHECK-DAG: @strong_variable = extern_weak global
20+
_ = strong_variable
21+
}
22+
23+
func testFunctions() {
24+
// CHECK-DAG: declare extern_weak void @always_available_function()
25+
always_available_function()
26+
}
27+
28+
// CHECK-DAG: @"OBJC_CLASS_$_NSNumber" = extern_weak global %objc_class
29+
// CHECK-DAG: @"OBJC_METACLASS_$_NSNumber" = extern_weak global %objc_class
30+
class CustomNumber: NSNumber {}

0 commit comments

Comments
 (0)