Skip to content

Commit bb33977

Browse files
committed
Add @_weakLinked and a corresponding SIL attribute
This is mostly intended to be used for testing at this point; in the long run, we want to be using availability information to decide whether to weak-link something or not. You'll notice a bunch of FIXMEs in the test case that we may not need now, but will probably need to handle in the future. Groundwork for doing backward-deployment execution tests.
1 parent a036033 commit bb33977

18 files changed

+353
-19
lines changed

include/swift/AST/Attr.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,12 @@ DECL_ATTR(_clangImporterSynthesizedType, ClangImporterSynthesizedType,
308308
LongAttribute | NotSerialized | RejectByParser | UserInaccessible,
309309
/*Not serialized*/74)
310310

311+
SIMPLE_DECL_ATTR(_weakLinked, WeakLinked,
312+
OnEnum | OnStruct | OnClass | OnProtocol |
313+
OnFunc | OnVar | OnSubscript | OnConstructor | OnEnumElement |
314+
UserInaccessible,
315+
75)
316+
311317
#undef TYPE_ATTR
312318
#undef DECL_ATTR_ALIAS
313319
#undef SIMPLE_DECL_ATTR

include/swift/IRGen/Linking.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -733,9 +733,12 @@ class LinkEntity {
733733
getSILGlobalVariable()->getDecl())
734734
return getSILGlobalVariable()->getDecl()->isWeakImported(module);
735735

736-
if (getKind() == Kind::SILFunction)
736+
if (getKind() == Kind::SILFunction) {
737737
if (auto clangOwner = getSILFunction()->getClangNodeOwner())
738738
return clangOwner->isWeakImported(module);
739+
if (getSILFunction()->isWeakLinked())
740+
return getSILFunction()->isAvailableExternally();
741+
}
739742

740743
if (!isDeclKind(getKind()))
741744
return false;

include/swift/SIL/SILFunction.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,9 @@ class SILFunction
171171
/// would indicate.
172172
unsigned HasCReferences : 1;
173173

174+
/// Whether cross-module references to this function should use weak linking.
175+
unsigned IsWeakLinked : 1;
176+
174177
/// If != OptimizationMode::NotSet, the optimization mode specified with an
175178
/// function attribute.
176179
OptimizationMode OptMode;
@@ -450,6 +453,16 @@ class SILFunction
450453
bool hasCReferences() const { return HasCReferences; }
451454
void setHasCReferences(bool value) { HasCReferences = value; }
452455

456+
/// Returns whether this function's symbol must always be weakly referenced
457+
/// across module boundaries.
458+
bool isWeakLinked() const { return IsWeakLinked; }
459+
/// Forces IRGen to treat references to this function as weak across module
460+
/// boundaries (i.e. if it has external linkage).
461+
void setWeakLinked(bool value = true) {
462+
assert(!IsWeakLinked && "already set");
463+
IsWeakLinked = value;
464+
}
465+
453466
/// Get the DeclContext of this function. (Debug info only).
454467
DeclContext *getDeclContext() const {
455468
return getLocation().getAsDeclContext();

include/swift/Serialization/ModuleFormat.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ const uint16_t VERSION_MAJOR = 0;
5454
/// in source control, you should also update the comment to briefly
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
57-
const uint16_t VERSION_MINOR = 398; // Private discriminators for type xrefs
57+
/// Don't worry about adhering to the 80-column limit for this line.
58+
const uint16_t VERSION_MINOR = 399; // Last change: @_weakLinked
5859

5960
using DeclIDField = BCFixed<31>;
6061

lib/AST/Decl.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,14 @@ bool Decl::isWeakImported(ModuleDecl *fromModule) const {
482482
return clangDecl->isWeakImported();
483483
}
484484

485-
// FIXME: Implement using AvailableAttr::getVersionAvailability().
485+
auto *containingModule = getModuleContext();
486+
if (containingModule == fromModule)
487+
return false;
488+
489+
if (getAttrs().hasAttribute<WeakLinkedAttr>())
490+
return true;
491+
492+
// FIXME: Also check availability when containingModule is resilient.
486493
return false;
487494
}
488495

lib/ParseSIL/ParseSIL.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -882,7 +882,7 @@ static bool parseDeclSILOptional(bool *isTransparent,
882882
IsThunk_t *isThunk, bool *isGlobalInit,
883883
Inline_t *inlineStrategy,
884884
OptimizationMode *optimizationMode,
885-
bool *isLet,
885+
bool *isLet, bool *isWeakLinked,
886886
SmallVectorImpl<std::string> *Semantics,
887887
SmallVectorImpl<ParsedSpecAttr> *SpecAttrs,
888888
ValueDecl **ClangDecl,
@@ -909,6 +909,8 @@ static bool parseDeclSILOptional(bool *isTransparent,
909909
*isThunk = IsReabstractionThunk;
910910
else if (isGlobalInit && SP.P.Tok.getText() == "global_init")
911911
*isGlobalInit = true;
912+
else if (isWeakLinked && SP.P.Tok.getText() == "_weakLinked")
913+
*isWeakLinked = true;
912914
else if (inlineStrategy && SP.P.Tok.getText() == "noinline")
913915
*inlineStrategy = NoInline;
914916
else if (optimizationMode && SP.P.Tok.getText() == "Onone")
@@ -5089,7 +5091,7 @@ bool SILParserTUState::parseDeclSIL(Parser &P) {
50895091
bool isTransparent = false;
50905092
IsSerialized_t isSerialized = IsNotSerialized;
50915093
IsThunk_t isThunk = IsNotThunk;
5092-
bool isGlobalInit = false;
5094+
bool isGlobalInit = false, isWeakLinked = false;
50935095
Inline_t inlineStrategy = InlineDefault;
50945096
OptimizationMode optimizationMode = OptimizationMode::NotSet;
50955097
SmallVector<std::string, 1> Semantics;
@@ -5099,7 +5101,7 @@ bool SILParserTUState::parseDeclSIL(Parser &P) {
50995101
if (parseSILLinkage(FnLinkage, P) ||
51005102
parseDeclSILOptional(&isTransparent, &isSerialized, &isThunk, &isGlobalInit,
51015103
&inlineStrategy, &optimizationMode, nullptr,
5102-
&Semantics, &SpecAttrs,
5104+
&isWeakLinked, &Semantics, &SpecAttrs,
51035105
&ClangDecl, &MRK, FunctionState) ||
51045106
P.parseToken(tok::at_sign, diag::expected_sil_function_name) ||
51055107
P.parseIdentifier(FnName, FnNameLoc, diag::expected_sil_function_name) ||
@@ -5125,6 +5127,7 @@ bool SILParserTUState::parseDeclSIL(Parser &P) {
51255127
FunctionState.F->setSerialized(IsSerialized_t(isSerialized));
51265128
FunctionState.F->setThunk(IsThunk_t(isThunk));
51275129
FunctionState.F->setGlobalInit(isGlobalInit);
5130+
FunctionState.F->setWeakLinked(isWeakLinked);
51285131
FunctionState.F->setInlineStrategy(inlineStrategy);
51295132
FunctionState.F->setOptimizationMode(optimizationMode);
51305133
FunctionState.F->setEffectsKind(MRK);
@@ -5257,7 +5260,7 @@ bool SILParserTUState::parseSILGlobal(Parser &P) {
52575260
if (parseSILLinkage(GlobalLinkage, P) ||
52585261
parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr,
52595262
nullptr, nullptr, &isLet, nullptr, nullptr, nullptr,
5260-
nullptr, State) ||
5263+
nullptr, nullptr, State) ||
52615264
P.parseToken(tok::at_sign, diag::expected_sil_value_name) ||
52625265
P.parseIdentifier(GlobalName, NameLoc, diag::expected_sil_value_name) ||
52635266
P.parseToken(tok::colon, diag::expected_sil_type))
@@ -5300,7 +5303,7 @@ bool SILParserTUState::parseSILVTable(Parser &P) {
53005303
IsSerialized_t Serialized = IsNotSerialized;
53015304
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr,
53025305
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
5303-
nullptr, VTableState))
5306+
nullptr, nullptr, VTableState))
53045307
return true;
53055308

53065309
// Parse the class name.
@@ -5650,7 +5653,7 @@ bool SILParserTUState::parseSILWitnessTable(Parser &P) {
56505653
IsSerialized_t isSerialized = IsNotSerialized;
56515654
if (parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr,
56525655
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
5653-
nullptr, WitnessState))
5656+
nullptr, nullptr, WitnessState))
56545657
return true;
56555658

56565659
Scope S(&P, ScopeKind::TopLevel);

lib/SIL/SILFunction.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ SILFunction::SILFunction(SILModule &Module, SILLinkage Linkage, StringRef Name,
9898
Serialized(isSerialized), Thunk(isThunk),
9999
ClassSubclassScope(unsigned(classSubclassScope)), GlobalInitFlag(false),
100100
InlineStrategy(inlineStrategy), Linkage(unsigned(Linkage)),
101-
HasCReferences(false),
101+
HasCReferences(false), IsWeakLinked(false),
102102
OptMode(OptimizationMode::NotSet), EffectsKindAttr(E),
103103
EntryCount(entryCount) {
104104
if (InsertBefore)

lib/SIL/SILModule.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,9 @@ static void addFunctionAttributes(SILFunction *F, DeclAttributes &Attrs,
310310
if (Attrs.hasAttribute<SILGenNameAttr>() ||
311311
Attrs.hasAttribute<CDeclAttr>())
312312
F->setHasCReferences(true);
313+
314+
if (Attrs.hasAttribute<WeakLinkedAttr>())
315+
F->setWeakLinked();
313316
}
314317

315318
SILFunction *SILModule::getOrCreateFunction(SILLocation loc,

lib/SIL/SILPrinter.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2280,7 +2280,9 @@ void SILFunction::print(SILPrintContext &PrintCtx) const {
22802280

22812281
if (isGlobalInit())
22822282
OS << "[global_init] ";
2283-
2283+
if (isWeakLinked())
2284+
OS << "[_weakLinked] ";
2285+
22842286
switch (getInlineStrategy()) {
22852287
case NoInline: OS << "[noinline] "; break;
22862288
case AlwaysInline: OS << "[always_inline] "; break;

lib/Sema/TypeCheckAttr.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ class AttributeEarlyChecker : public AttributeVisitor<AttributeEarlyChecker> {
112112
IGNORED_ATTR(UIApplicationMain)
113113
IGNORED_ATTR(UnsafeNoObjCTaggedPointer)
114114
IGNORED_ATTR(Versioned)
115+
IGNORED_ATTR(WeakLinked)
115116
#undef IGNORED_ATTR
116117

117118
// @noreturn has been replaced with a 'Never' return type.
@@ -833,6 +834,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
833834
IGNORED_ATTR(Testable)
834835
IGNORED_ATTR(Transparent)
835836
IGNORED_ATTR(WarnUnqualifiedAccess)
837+
IGNORED_ATTR(WeakLinked)
836838
#undef IGNORED_ATTR
837839

838840
void visitAvailableAttr(AvailableAttr *attr);

lib/Sema/TypeCheckDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6527,6 +6527,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
65276527
UNINTERESTING_ATTR(DowngradeExhaustivityCheck)
65286528
UNINTERESTING_ATTR(ImplicitlyUnwrappedOptional)
65296529
UNINTERESTING_ATTR(ClangImporterSynthesizedType)
6530+
UNINTERESTING_ATTR(WeakLinked)
65306531
#undef UNINTERESTING_ATTR
65316532

65326533
void visitAvailableAttr(AvailableAttr *attr) {

lib/Serialization/DeserializeSIL.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -413,12 +413,12 @@ SILFunction *SILDeserializer::readSILFunction(DeclID FID,
413413
GenericEnvironmentID genericEnvID;
414414
unsigned rawLinkage, isTransparent, isSerialized, isThunk, isGlobal,
415415
inlineStrategy, optimizationMode, effect, numSpecAttrs,
416-
hasQualifiedOwnership;
416+
hasQualifiedOwnership, isWeakLinked;
417417
ArrayRef<uint64_t> SemanticsIDs;
418418
SILFunctionLayout::readRecord(scratch, rawLinkage, isTransparent, isSerialized,
419419
isThunk, isGlobal, inlineStrategy,
420-
optimizationMode, effect,
421-
numSpecAttrs, hasQualifiedOwnership, funcTyID,
420+
optimizationMode, effect, numSpecAttrs,
421+
hasQualifiedOwnership, isWeakLinked, funcTyID,
422422
genericEnvID, clangNodeOwnerID, SemanticsIDs);
423423

424424
if (funcTyID == 0) {
@@ -498,6 +498,7 @@ SILFunction *SILDeserializer::readSILFunction(DeclID FID,
498498
fn->setGlobalInit(isGlobal == 1);
499499
fn->setEffectsKind((EffectsKind)effect);
500500
fn->setOptimizationMode((OptimizationMode)optimizationMode);
501+
fn->setWeakLinked(isWeakLinked);
501502
if (clangNodeOwner)
502503
fn->setClangNodeOwner(clangNodeOwner);
503504
for (auto ID : SemanticsIDs) {
@@ -2405,12 +2406,12 @@ bool SILDeserializer::hasSILFunction(StringRef Name,
24052406
GenericEnvironmentID genericEnvID;
24062407
unsigned rawLinkage, isTransparent, isSerialized, isThunk, isGlobal,
24072408
inlineStrategy, optimizationMode, effect, numSpecAttrs,
2408-
hasQualifiedOwnership;
2409+
hasQualifiedOwnership, isWeakLinked;
24092410
ArrayRef<uint64_t> SemanticsIDs;
24102411
SILFunctionLayout::readRecord(scratch, rawLinkage, isTransparent, isSerialized,
24112412
isThunk, isGlobal, inlineStrategy,
2412-
optimizationMode, effect,
2413-
numSpecAttrs, hasQualifiedOwnership, funcTyID,
2413+
optimizationMode, effect, numSpecAttrs,
2414+
hasQualifiedOwnership, isWeakLinked, funcTyID,
24142415
genericEnvID, clangOwnerID, SemanticsIDs);
24152416
auto linkage = fromStableSILLinkage(rawLinkage);
24162417
if (!linkage) {

lib/Serialization/SILFormat.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ namespace sil_block {
280280
BCFixed<2>, // side effect info.
281281
BCVBR<8>, // number of specialize attributes
282282
BCFixed<1>, // has qualified ownership
283+
BCFixed<1>, // must be weakly referenced
283284
TypeIDField, // SILFunctionType
284285
GenericEnvironmentIDField,
285286
DeclIDField, // ClangNode owner

lib/Serialization/SerializeSIL.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,8 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) {
379379
(unsigned)F.isThunk(), (unsigned)F.isGlobalInit(),
380380
(unsigned)F.getInlineStrategy(), (unsigned)F.getOptimizationMode(),
381381
(unsigned)F.getEffectsKind(),
382-
(unsigned)numSpecAttrs, (unsigned)F.hasQualifiedOwnership(), FnID,
383-
genericEnvID, clangNodeOwnerID, SemanticsIDs);
382+
(unsigned)numSpecAttrs, (unsigned)F.hasQualifiedOwnership(),
383+
F.isWeakLinked(), FnID, genericEnvID, clangNodeOwnerID, SemanticsIDs);
384384

385385
if (NoBody)
386386
return;
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
@_weakLinked
2+
public func fn() {}
3+
4+
@_weakLinked
5+
public var globalStored = 0
6+
7+
@_weakLinked
8+
public var globalComputed: Int {
9+
get { return 1 }
10+
set {}
11+
}
12+
13+
public struct S {
14+
@_weakLinked
15+
public func fn() {}
16+
17+
@_weakLinked
18+
public var storedProp = 0
19+
20+
@_weakLinked
21+
public var computedProp: Int {
22+
get { return 1 }
23+
set {}
24+
}
25+
26+
@_weakLinked
27+
public init() {}
28+
29+
@_weakLinked
30+
public subscript(_: Int) -> Int {
31+
get { return 1 }
32+
set {}
33+
}
34+
}
35+
36+
public enum E {
37+
case strong
38+
39+
@_weakLinked
40+
case weak
41+
42+
case strongAssoc(Int)
43+
44+
@_weakLinked
45+
case weakAssoc(Int)
46+
}
47+
48+
open class C {
49+
@_weakLinked
50+
open func fn() {}
51+
52+
@_weakLinked
53+
open var storedProp = 0
54+
55+
@_weakLinked
56+
open var computedProp: Int {
57+
get { return 1 }
58+
set {}
59+
}
60+
61+
@_weakLinked
62+
public init() {}
63+
64+
@_weakLinked
65+
open subscript(_: Int) -> Int {
66+
get { return 1 }
67+
set {}
68+
}
69+
}
70+
71+
public protocol P {
72+
@_weakLinked
73+
func fn()
74+
75+
@_weakLinked
76+
var prop: Int { get set }
77+
78+
@_weakLinked
79+
init()
80+
81+
@_weakLinked
82+
subscript(_: Int) -> Int { get set }
83+
}
84+
85+
@_weakLinked
86+
public struct WeakS {}
87+
88+
@_weakLinked
89+
public enum WeakE {}
90+
91+
@_weakLinked
92+
open class WeakC {}
93+
94+
@_weakLinked
95+
public protocol WeakP {}
96+
97+
98+
@_weakLinked
99+
public struct GenericS<T> {}
100+
101+
@_weakLinked
102+
public enum GenericE<T> {}
103+
104+
@_weakLinked
105+
open class GenericC<T> {}
File renamed without changes.

test/IRGen/weak_import_native.sil

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -primary-file %s -emit-ir | %FileCheck %s
3+
4+
sil_stage canonical
5+
6+
// CHECK-DAG: define{{( protected)?}} swiftcc void @weakButDefined() {{#[0-9]+}} {
7+
sil public [_weakLinked] @weakButDefined : $@convention(thin) () -> () {
8+
%unit = tuple()
9+
return %unit : $()
10+
}
11+
12+
// CHECK-DAG: declare extern_weak swiftcc void @weakExternal()
13+
sil public_external [_weakLinked] @weakExternal : $@convention(thin) () -> ()
14+
15+
sil [_weakLinked] @testWeak : $@convention(thin) () -> () {
16+
%weakButDefined = function_ref @weakButDefined : $@convention(thin) () -> ()
17+
%wbdResult = apply %weakButDefined() : $@convention(thin) () -> ()
18+
%weakExternal = function_ref @weakExternal : $@convention(thin) () -> ()
19+
%weResult = apply %weakExternal() : $@convention(thin) () -> ()
20+
%unit = tuple()
21+
return %unit : $()
22+
}
23+

0 commit comments

Comments
 (0)