Skip to content

Commit 3a59e7c

Browse files
committed
SIL: Serialize availability with the SIL function, not just a weak imported flag
The weak imported flag is now only set if the attribute is unconditionally weak linked, which is the case when it or one of its parent contexts has a @_weakLinked attribute. To correctly handle weak linking based availability with serialized SIL functions, we need to serialize the actual version tuple when the SIL function was introduced. This is because the deployment target of the client app can be older than the deployment target that the original module was built with. Fixes <rdar://problem/52783668>.
1 parent a0e160e commit 3a59e7c

21 files changed

+294
-112
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,8 @@ ERROR(expected_sil_function_type, none,
640640
"sil function expected to have SIL function type", ())
641641
ERROR(sil_dynamically_replaced_func_not_found,none,
642642
"dynamically replaced function not found %0", (Identifier))
643+
ERROR(sil_availability_expected_version,none,
644+
"expected version number in 'available' attribute", ())
643645

644646
// SIL Stage
645647
ERROR(expected_sil_stage_name, none,

include/swift/SIL/SILFunction.h

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define SWIFT_SIL_SILFUNCTION_H
1919

2020
#include "swift/AST/ASTNode.h"
21+
#include "swift/AST/Availability.h"
2122
#include "swift/AST/ResilienceExpansion.h"
2223
#include "swift/Basic/ProfileCounter.h"
2324
#include "swift/SIL/SILBasicBlock.h"
@@ -178,6 +179,10 @@ class SILFunction
178179
/// Contains Function Entry Count
179180
ProfileCounter EntryCount;
180181

182+
/// The availability used to determine if declarations of this function
183+
/// should use weak linking.
184+
AvailabilityContext Availability;
185+
181186
/// This is the number of uses of this SILFunction inside the SIL.
182187
/// It does not include references from debug scopes.
183188
unsigned RefCount = 0;
@@ -216,8 +221,9 @@ class SILFunction
216221
/// would indicate.
217222
unsigned HasCReferences : 1;
218223

219-
/// Whether cross-module references to this function should use weak linking.
220-
unsigned IsWeakLinked : 1;
224+
/// Whether cross-module references to this function should always use
225+
/// weak linking.
226+
unsigned IsWeakImported : 1;
221227

222228
/// Whether the implementation can be dynamically replaced.
223229
unsigned IsDynamicReplaceable : 1;
@@ -591,16 +597,26 @@ class SILFunction
591597
bool hasCReferences() const { return HasCReferences; }
592598
void setHasCReferences(bool value) { HasCReferences = value; }
593599

600+
/// Returns the availability context used to determine if the function's
601+
/// symbol should be weakly referenced across module boundaries.
602+
AvailabilityContext getAvailabilityForLinkage() const {
603+
return Availability;
604+
}
605+
606+
void setAvailabilityForLinkage(AvailabilityContext availability) {
607+
Availability = availability;
608+
}
609+
594610
/// Returns whether this function's symbol must always be weakly referenced
595611
/// across module boundaries.
596-
bool isWeakLinked() const { return IsWeakLinked; }
597-
/// Forces IRGen to treat references to this function as weak across module
598-
/// boundaries (i.e. if it has external linkage).
599-
void setWeakLinked(bool value = true) {
600-
assert(!IsWeakLinked && "already set");
601-
IsWeakLinked = value;
612+
bool isAlwaysWeakImported() const { return IsWeakImported; }
613+
614+
void setAlwaysWeakImported(bool value) {
615+
IsWeakImported = value;
602616
}
603617

618+
bool isWeakImported() const;
619+
604620
/// Returns whether this function implementation can be dynamically replaced.
605621
IsDynamicallyReplaceable_t isDynamicallyReplaceable() const {
606622
return IsDynamicallyReplaceable_t(IsDynamicReplaceable);

lib/IRGen/Linking.cpp

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
#include "IRGenMangler.h"
1919
#include "IRGenModule.h"
2020
#include "swift/AST/ASTMangler.h"
21-
#include "swift/AST/Availability.h"
2221
#include "swift/AST/IRGenOptions.h"
2322
#include "swift/ClangImporter/ClangModule.h"
2423
#include "swift/SIL/SILGlobalVariable.h"
@@ -966,22 +965,13 @@ bool LinkEntity::isWeakImported(ModuleDecl *module) const {
966965
switch (getKind()) {
967966
case Kind::SILGlobalVariable:
968967
if (getSILGlobalVariable()->getDecl()) {
969-
return getSILGlobalVariable()->getDecl()
970-
->isWeakImported(module);
968+
return getSILGlobalVariable()->getDecl()->isWeakImported(module);
971969
}
972970
return false;
973971
case Kind::DynamicallyReplaceableFunctionKey:
974972
case Kind::DynamicallyReplaceableFunctionVariable:
975973
case Kind::SILFunction: {
976-
// For imported functions check the Clang declaration.
977-
if (auto clangOwner = getSILFunction()->getClangNodeOwner())
978-
return clangOwner->isWeakImported(module);
979-
980-
// For native functions check a flag on the SILFunction
981-
// itself.
982-
if (getSILFunction()->isWeakLinked())
983-
return getSILFunction()->isAvailableExternally();
984-
return false;
974+
return getSILFunction()->isWeakImported();
985975
}
986976

987977
case Kind::AssociatedConformanceDescriptor:

lib/ParseSIL/ParseSIL.cpp

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -985,7 +985,9 @@ static bool parseDeclSILOptional(bool *isTransparent,
985985
bool *isGlobalInit,
986986
Inline_t *inlineStrategy,
987987
OptimizationMode *optimizationMode,
988-
bool *isLet, bool *isWeakLinked,
988+
bool *isLet,
989+
bool *isWeakImported,
990+
AvailabilityContext *availability,
989991
bool *isWithoutActuallyEscapingThunk,
990992
SmallVectorImpl<std::string> *Semantics,
991993
SmallVectorImpl<ParsedSpecAttr> *SpecAttrs,
@@ -1027,14 +1029,27 @@ static bool parseDeclSILOptional(bool *isTransparent,
10271029
*isWithoutActuallyEscapingThunk = true;
10281030
else if (isGlobalInit && SP.P.Tok.getText() == "global_init")
10291031
*isGlobalInit = true;
1030-
else if (isWeakLinked && SP.P.Tok.getText() == "_weakLinked")
1032+
else if (isWeakImported && SP.P.Tok.getText() == "weak_imported") {
10311033
if (M.getASTContext().LangOpts.Target.isOSBinFormatCOFF())
10321034
SP.P.diagnose(SP.P.Tok, diag::attr_unsupported_on_target,
10331035
SP.P.Tok.getText(),
10341036
M.getASTContext().LangOpts.Target.str());
10351037
else
1036-
*isWeakLinked = true;
1037-
else if (inlineStrategy && SP.P.Tok.getText() == "noinline")
1038+
*isWeakImported = true;
1039+
} else if (availability && SP.P.Tok.getText() == "available") {
1040+
SP.P.consumeToken(tok::identifier);
1041+
1042+
SourceRange range;
1043+
llvm::VersionTuple version;
1044+
if (SP.P.parseVersionTuple(version, range,
1045+
diag::sil_availability_expected_version))
1046+
return true;
1047+
1048+
*availability = AvailabilityContext(VersionRange::allGTE(version));
1049+
1050+
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
1051+
continue;
1052+
} else if (inlineStrategy && SP.P.Tok.getText() == "noinline")
10381053
*inlineStrategy = NoInline;
10391054
else if (optimizationMode && SP.P.Tok.getText() == "Onone")
10401055
*optimizationMode = OptimizationMode::NoOptimization;
@@ -5402,7 +5417,8 @@ bool SILParserTUState::parseDeclSIL(Parser &P) {
54025417
IsExactSelfClass_t isExactSelfClass = IsNotExactSelfClass;
54035418
bool hasOwnershipSSA = false;
54045419
IsThunk_t isThunk = IsNotThunk;
5405-
bool isGlobalInit = false, isWeakLinked = false;
5420+
bool isGlobalInit = false, isWeakImported = false;
5421+
AvailabilityContext availability = AvailabilityContext::alwaysAvailable();
54065422
bool isWithoutActuallyEscapingThunk = false;
54075423
Inline_t inlineStrategy = InlineDefault;
54085424
OptimizationMode optimizationMode = OptimizationMode::NotSet;
@@ -5417,7 +5433,7 @@ bool SILParserTUState::parseDeclSIL(Parser &P) {
54175433
&isTransparent, &isSerialized, &isCanonical, &hasOwnershipSSA,
54185434
&isThunk, &isDynamic, &isExactSelfClass, &DynamicallyReplacedFunction,
54195435
&objCReplacementFor, &isGlobalInit, &inlineStrategy, &optimizationMode, nullptr,
5420-
&isWeakLinked, &isWithoutActuallyEscapingThunk, &Semantics,
5436+
&isWeakImported, &availability, &isWithoutActuallyEscapingThunk, &Semantics,
54215437
&SpecAttrs, &ClangDecl, &MRK, FunctionState, M) ||
54225438
P.parseToken(tok::at_sign, diag::expected_sil_function_name) ||
54235439
P.parseIdentifier(FnName, FnNameLoc, diag::expected_sil_function_name) ||
@@ -5452,7 +5468,8 @@ bool SILParserTUState::parseDeclSIL(Parser &P) {
54525468
if (!objCReplacementFor.empty())
54535469
FunctionState.F->setObjCReplacement(objCReplacementFor);
54545470
FunctionState.F->setGlobalInit(isGlobalInit);
5455-
FunctionState.F->setWeakLinked(isWeakLinked);
5471+
FunctionState.F->setAlwaysWeakImported(isWeakImported);
5472+
FunctionState.F->setAvailabilityForLinkage(availability);
54565473
FunctionState.F->setWithoutActuallyEscapingThunk(
54575474
isWithoutActuallyEscapingThunk);
54585475
FunctionState.F->setInlineStrategy(inlineStrategy);
@@ -5642,7 +5659,7 @@ bool SILParserTUState::parseSILGlobal(Parser &P) {
56425659
nullptr, nullptr, nullptr, nullptr, nullptr,
56435660
nullptr, nullptr,
56445661
&isLet, nullptr, nullptr, nullptr, nullptr, nullptr,
5645-
nullptr, State, M) ||
5662+
nullptr, nullptr, State, M) ||
56465663
P.parseToken(tok::at_sign, diag::expected_sil_value_name) ||
56475664
P.parseIdentifier(GlobalName, NameLoc, diag::expected_sil_value_name) ||
56485665
P.parseToken(tok::colon, diag::expected_sil_type))
@@ -5691,7 +5708,7 @@ bool SILParserTUState::parseSILProperty(Parser &P) {
56915708
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr,
56925709
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
56935710
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
5694-
nullptr, nullptr, SP, M))
5711+
nullptr, nullptr, nullptr, SP, M))
56955712
return true;
56965713

56975714
ValueDecl *VD;
@@ -5760,7 +5777,7 @@ bool SILParserTUState::parseSILVTable(Parser &P) {
57605777
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr,
57615778
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
57625779
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
5763-
nullptr, nullptr,
5780+
nullptr, nullptr, nullptr,
57645781
VTableState, M))
57655782
return true;
57665783

@@ -6295,7 +6312,7 @@ bool SILParserTUState::parseSILWitnessTable(Parser &P) {
62956312
if (parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
62966313
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
62976314
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
6298-
nullptr, nullptr,
6315+
nullptr, nullptr, nullptr,
62996316
WitnessState, M))
63006317
return true;
63016318

lib/SIL/SILFunction.cpp

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@
1818
#include "swift/SIL/SILProfiler.h"
1919
#include "swift/SIL/CFG.h"
2020
#include "swift/SIL/PrettyStackTrace.h"
21+
#include "swift/AST/Availability.h"
2122
#include "swift/AST/GenericEnvironment.h"
23+
#include "swift/AST/Module.h"
2224
#include "swift/Basic/OptimizationMode.h"
2325
#include "swift/Basic/Statistic.h"
2426
#include "llvm/ADT/Optional.h"
2527
#include "llvm/Support/CommandLine.h"
2628
#include "llvm/Support/GraphWriter.h"
29+
#include "clang/AST/Decl.h"
2730

2831
using namespace swift;
2932
using namespace Lowering;
@@ -93,11 +96,13 @@ SILFunction::SILFunction(SILModule &Module, SILLinkage Linkage, StringRef Name,
9396
IsExactSelfClass_t isExactSelfClass)
9497
: Module(Module), Name(Name), LoweredType(LoweredType),
9598
GenericEnv(genericEnv), SpecializationInfo(nullptr),
96-
EntryCount(entryCount), Bare(isBareSILFunction), Transparent(isTrans),
99+
EntryCount(entryCount),
100+
Availability(AvailabilityContext::alwaysAvailable()),
101+
Bare(isBareSILFunction), Transparent(isTrans),
97102
Serialized(isSerialized), Thunk(isThunk),
98103
ClassSubclassScope(unsigned(classSubclassScope)), GlobalInitFlag(false),
99104
InlineStrategy(inlineStrategy), Linkage(unsigned(Linkage)),
100-
HasCReferences(false), IsWeakLinked(false),
105+
HasCReferences(false), IsWeakImported(false),
101106
IsDynamicReplaceable(isDynamic),
102107
ExactSelfClass(isExactSelfClass),
103108
Inlined(false), Zombie(false), HasOwnership(true),
@@ -259,6 +264,27 @@ bool SILFunction::isTypeABIAccessible(SILType type) const {
259264
return getModule().isTypeABIAccessible(type, getResilienceExpansion());
260265
}
261266

267+
bool SILFunction::isWeakImported() const {
268+
// For imported functions check the Clang declaration.
269+
if (ClangNodeOwner)
270+
return ClangNodeOwner->getClangDecl()->isWeakImported();
271+
272+
// For native functions check a flag on the SILFunction
273+
// itself.
274+
if (!isAvailableExternally())
275+
return false;
276+
277+
if (isAlwaysWeakImported())
278+
return true;
279+
280+
if (Availability.isAlwaysAvailable())
281+
return false;
282+
283+
auto fromContext = AvailabilityContext::forDeploymentTarget(
284+
getASTContext());
285+
return !fromContext.isContainedIn(Availability);
286+
}
287+
262288
SILBasicBlock *SILFunction::createBasicBlock() {
263289
return new (getModule()) SILBasicBlock(this, nullptr, false);
264290
}

lib/SIL/SILFunctionBuilder.cpp

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -162,17 +162,8 @@ SILFunctionBuilder::getOrCreateFunction(SILLocation loc, SILDeclRef constant,
162162
if (constant.isForeign && decl->hasClangNode())
163163
F->setClangNodeOwner(decl);
164164

165-
if (decl->isAlwaysWeakImported())
166-
F->setWeakLinked();
167-
else {
168-
auto containingContext = decl->getAvailabilityForLinkage();
169-
if (!containingContext.isAlwaysAvailable()) {
170-
auto fromContext = AvailabilityContext::forDeploymentTarget(
171-
decl->getASTContext());
172-
if (!fromContext.isContainedIn(containingContext))
173-
F->setWeakLinked();
174-
}
175-
}
165+
F->setAvailabilityForLinkage(decl->getAvailabilityForLinkage());
166+
F->setAlwaysWeakImported(decl->isAlwaysWeakImported());
176167

177168
if (auto *accessor = dyn_cast<AccessorDecl>(decl)) {
178169
auto *storage = accessor->getStorage();

lib/SIL/SILPrinter.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2332,8 +2332,13 @@ void SILFunction::print(SILPrintContext &PrintCtx) const {
23322332

23332333
if (isGlobalInit())
23342334
OS << "[global_init] ";
2335-
if (isWeakLinked())
2336-
OS << "[_weakLinked] ";
2335+
if (isAlwaysWeakImported())
2336+
OS << "[weak_imported] ";
2337+
auto availability = getAvailabilityForLinkage();
2338+
if (!availability.isAlwaysAvailable()) {
2339+
auto version = availability.getOSVersion().getLowerEndpoint();
2340+
OS << "[available " << version.getAsString() << "] ";
2341+
}
23372342

23382343
switch (getInlineStrategy()) {
23392344
case NoInline: OS << "[noinline] "; break;

lib/Serialization/Deserialization.cpp

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3872,18 +3872,6 @@ llvm::Error DeclDeserializer::deserializeDeclAttributes() {
38723872
}
38733873

38743874
case decls_block::Available_DECL_ATTR: {
3875-
#define LIST_VER_TUPLE_PIECES(X)\
3876-
X##_Major, X##_Minor, X##_Subminor, X##_HasMinor, X##_HasSubminor
3877-
#define DEF_VER_TUPLE_PIECES(X) unsigned LIST_VER_TUPLE_PIECES(X)
3878-
#define DECODE_VER_TUPLE(X)\
3879-
if (X##_HasMinor) {\
3880-
if (X##_HasSubminor)\
3881-
X = llvm::VersionTuple(X##_Major, X##_Minor, X##_Subminor);\
3882-
else\
3883-
X = llvm::VersionTuple(X##_Major, X##_Minor);\
3884-
}\
3885-
else X = llvm::VersionTuple(X##_Major);
3886-
38873875
bool isImplicit;
38883876
bool isUnavailable;
38893877
bool isDeprecated;
@@ -3932,10 +3920,6 @@ llvm::Error DeclDeserializer::deserializeDeclAttributes() {
39323920
Obsoleted, SourceRange(),
39333921
platformAgnostic, isImplicit);
39343922
break;
3935-
3936-
#undef DEF_VER_TUPLE_PIECES
3937-
#undef LIST_VER_TUPLE_PIECES
3938-
#undef DECODE_VER_TUPLE
39393923
}
39403924

39413925
case decls_block::ObjC_DECL_ATTR: {

lib/Serialization/DeserializeSIL.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -469,13 +469,15 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn,
469469
unsigned rawLinkage, isTransparent, isSerialized, isThunk,
470470
isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy,
471471
optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership,
472-
isWeakLinked, isDynamic, isExactSelfClass;
472+
isWeakImported, LIST_VER_TUPLE_PIECES(available),
473+
isDynamic, isExactSelfClass;
473474
ArrayRef<uint64_t> SemanticsIDs;
474475
SILFunctionLayout::readRecord(
475476
scratch, rawLinkage, isTransparent, isSerialized, isThunk,
476477
isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy,
477478
optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership,
478-
isWeakLinked, isDynamic, isExactSelfClass,
479+
isWeakImported, LIST_VER_TUPLE_PIECES(available),
480+
isDynamic, isExactSelfClass,
479481
funcTyID, replacedFunctionID, genericSigID,
480482
clangNodeOwnerID, SemanticsIDs);
481483

@@ -580,7 +582,15 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn,
580582
fn->setGlobalInit(isGlobal == 1);
581583
fn->setEffectsKind(EffectsKind(effect));
582584
fn->setOptimizationMode(OptimizationMode(optimizationMode));
583-
fn->setWeakLinked(isWeakLinked);
585+
fn->setAlwaysWeakImported(isWeakImported);
586+
587+
llvm::VersionTuple available;
588+
DECODE_VER_TUPLE(available);
589+
fn->setAvailabilityForLinkage(
590+
available.empty()
591+
? AvailabilityContext::alwaysAvailable()
592+
: AvailabilityContext(VersionRange::allGTE(available)));
593+
584594
fn->setIsDynamic(IsDynamicallyReplaceable_t(isDynamic));
585595
fn->setIsExactSelfClass(IsExactSelfClass_t(isExactSelfClass));
586596
if (replacedFunction)
@@ -2539,13 +2549,15 @@ bool SILDeserializer::hasSILFunction(StringRef Name,
25392549
unsigned rawLinkage, isTransparent, isSerialized, isThunk,
25402550
isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy,
25412551
optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership,
2542-
isWeakLinked, isDynamic, isExactSelfClass;
2552+
isWeakImported, LIST_VER_TUPLE_PIECES(available),
2553+
isDynamic, isExactSelfClass;
25432554
ArrayRef<uint64_t> SemanticsIDs;
25442555
SILFunctionLayout::readRecord(
25452556
scratch, rawLinkage, isTransparent, isSerialized, isThunk,
25462557
isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy,
25472558
optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership,
2548-
isWeakLinked, isDynamic, isExactSelfClass,
2559+
isWeakImported, LIST_VER_TUPLE_PIECES(available),
2560+
isDynamic, isExactSelfClass,
25492561
funcTyID, replacedFunctionID, genericSigID,
25502562
clangOwnerID, SemanticsIDs);
25512563
auto linkage = fromStableSILLinkage(rawLinkage);

0 commit comments

Comments
 (0)