Skip to content

Commit b963e14

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

File tree

7 files changed

+80
-16
lines changed

7 files changed

+80
-16
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: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2487,10 +2487,23 @@ void IRGenModule::emitGlobalDecl(Decl *D) {
24872487
Address IRGenModule::getAddrOfSILGlobalVariable(SILGlobalVariable *var,
24882488
const TypeInfo &ti,
24892489
ForDefinition_t forDefinition) {
2490+
LinkEntity entity = LinkEntity::forSILGlobalVariable(var, *this);
2491+
LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
2492+
24902493
if (auto clangDecl = var->getClangDecl()) {
24912494
auto addr = getAddrOfClangGlobalDecl(cast<clang::VarDecl>(clangDecl),
24922495
forDefinition);
24932496

2497+
// Override the linkage computed by Clang if the decl is from another
2498+
// module that imported @_weakLinked.
2499+
//
2500+
// FIXME: We should be able to set the linkage unconditionally here but
2501+
// some fixes are needed for Cxx interop.
2502+
if (auto globalVar = dyn_cast<llvm::GlobalVariable>(addr)) {
2503+
if (getSwiftModule()->isImportedAsWeakLinked(var->getDecl()))
2504+
globalVar->setLinkage(link.getLinkage());
2505+
}
2506+
24942507
// If we're not emitting this to define it, make sure we cast it to the
24952508
// right type.
24962509
if (!forDefinition) {
@@ -2503,7 +2516,6 @@ Address IRGenModule::getAddrOfSILGlobalVariable(SILGlobalVariable *var,
25032516
return Address(addr, alignment);
25042517
}
25052518

2506-
LinkEntity entity = LinkEntity::forSILGlobalVariable(var, *this);
25072519
ResilienceExpansion expansion = getResilienceExpansionForLayout(var);
25082520

25092521
llvm::Type *storageType;
@@ -2549,7 +2561,6 @@ Address IRGenModule::getAddrOfSILGlobalVariable(SILGlobalVariable *var,
25492561

25502562
// Check whether we've created the global variable already.
25512563
// FIXME: We should integrate this into the LinkEntity cache more cleanly.
2552-
LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
25532564
auto gvar = Module.getGlobalVariable(link.getName(), /*allowInternal*/ true);
25542565
if (gvar) {
25552566
if (forDefinition)
@@ -3222,6 +3233,7 @@ llvm::Function *IRGenModule::getAddrOfSILFunction(
32223233
}
32233234
}
32243235

3236+
LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
32253237
bool isDefinition = f->isDefinition();
32263238
bool hasOrderNumber =
32273239
isDefinition && !shouldCallPreviousImplementation;
@@ -3242,8 +3254,16 @@ llvm::Function *IRGenModule::getAddrOfSILFunction(
32423254
if (clangAddr) {
32433255
fn = dyn_cast<llvm::Function>(clangAddr->stripPointerCasts());
32443256

3245-
// If we have a function, move it to the appropriate position.
32463257
if (fn) {
3258+
// Override the linkage computed by Clang if the decl is from another
3259+
// module that imported @_weakLinked.
3260+
//
3261+
// FIXME: We should be able to set the linkage unconditionally here but
3262+
// some fixes are needed for Cxx interop.
3263+
if (!forDefinition && f->isWeakImportedByModule())
3264+
fn->setLinkage(link.getLinkage());
3265+
3266+
// If we have a function, move it to the appropriate position.
32473267
if (hasOrderNumber) {
32483268
auto &fnList = Module.getFunctionList();
32493269
fnList.remove(fn);
@@ -3264,8 +3284,6 @@ llvm::Function *IRGenModule::getAddrOfSILFunction(
32643284
getSignature(f->getLoweredFunctionType(), fpKind);
32653285
addLLVMFunctionAttributes(f, signature);
32663286

3267-
LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
3268-
32693287
fn = createFunction(*this, link, signature, insertBefore,
32703288
f->getOptimizationMode(), shouldEmitStackProtector(f));
32713289

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)