Skip to content

Commit d672733

Browse files
authored
Merge pull request #27104 from slavapestov/sil-weak-linking-fix-5.1-08-28
Fix bad interaction between SIL deserialization and weak linking [5.1 08/28]
2 parents 921f508 + 80aae9e commit d672733

31 files changed

+431
-206
lines changed

include/swift/AST/Decl.h

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -975,9 +975,31 @@ class alignas(1 << DeclAlignInBits) Decl {
975975

976976
bool isPrivateStdlibDecl(bool treatNonBuiltinProtocolsAsPublic = true) const;
977977

978-
/// Whether this declaration is weak-imported.
979-
bool isWeakImported(ModuleDecl *fromModule,
980-
AvailabilityContext fromContext) const;
978+
AvailabilityContext getAvailabilityForLinkage() const;
979+
980+
/// Whether this declaration or one of its outer contexts has the
981+
/// @_weakLinked attribute.
982+
bool isAlwaysWeakImported() const;
983+
984+
/// Whether this declaration is weak-imported from the given module,
985+
/// either because of the presence of the @_weakLinked attribute, or
986+
/// because of availability.
987+
///
988+
/// Note that \p fromModule should either be the "main module" or
989+
/// nullptr. (This is because when it is non-null, we query the
990+
/// current deployment target, and not the deployment target that
991+
/// the module was built with.)
992+
///
993+
/// If \p fromModule is the main module, this returns false when the
994+
/// declaration is part of the main module, or if the declaration is
995+
/// at least as available as the current deployment target.
996+
///
997+
/// If \p fromModule is null, we instead return true if the
998+
/// declaration is meant to be weak linked with _some_ deployment
999+
/// target; that is, the presence of the @_weakLinked attribute or
1000+
/// any kind of availability is enough, irrespective of the current
1001+
/// deployment target.
1002+
bool isWeakImported(ModuleDecl *fromModule) const;
9811003

9821004
/// Returns true if the nature of this declaration allows overrides.
9831005
/// Note that this does not consider whether it is final or whether

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,8 @@ ERROR(expected_sil_function_type, none,
631631
"sil function expected to have SIL function type", ())
632632
ERROR(sil_dynamically_replaced_func_not_found,none,
633633
"dynamically replaced function not found %0", (Identifier))
634+
ERROR(sil_availability_expected_version,none,
635+
"expected version number in 'available' attribute", ())
634636

635637
// SIL Stage
636638
ERROR(expected_sil_stage_name, none,

include/swift/AST/ProtocolConformance.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,8 +349,7 @@ class RootProtocolConformance : public ProtocolConformance {
349349
bool isInvalid() const;
350350

351351
/// Whether this conformance is weak-imported.
352-
bool isWeakImported(ModuleDecl *fromModule,
353-
AvailabilityContext fromContext) const;
352+
bool isWeakImported(ModuleDecl *fromModule) const;
354353

355354
bool hasWitness(ValueDecl *requirement) const;
356355
Witness getWitness(ValueDecl *requirement, LazyResolver *resolver) const;

include/swift/IRGen/Linking.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,8 +1102,7 @@ class LinkEntity {
11021102
}
11031103

11041104
/// Determine whether this entity will be weak-imported.
1105-
bool isWeakImported(ModuleDecl *module,
1106-
AvailabilityContext fromContext) const;
1105+
bool isWeakImported(ModuleDecl *module) const;
11071106

11081107
/// Return the source file whose codegen should trigger emission of this
11091108
/// link entity, if one can be identified.
@@ -1173,7 +1172,6 @@ class LinkInfo {
11731172

11741173
static LinkInfo get(const UniversalLinkageInfo &linkInfo,
11751174
ModuleDecl *swiftModule,
1176-
AvailabilityContext availabilityContext,
11771175
const LinkEntity &entity,
11781176
ForDefinition_t forDefinition);
11791177

include/swift/SIL/SILFunction.h

Lines changed: 63 additions & 43 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"
@@ -160,6 +161,27 @@ class SILFunction
160161

161162
Identifier ObjCReplacementFor;
162163

164+
/// The function's set of semantics attributes.
165+
///
166+
/// TODO: Why is this using a std::string? Why don't we use uniqued
167+
/// StringRefs?
168+
std::vector<std::string> SemanticsAttrSet;
169+
170+
/// The function's remaining set of specialize attributes.
171+
std::vector<SILSpecializeAttr*> SpecializeAttrSet;
172+
173+
/// Has value if there's a profile for this function
174+
/// Contains Function Entry Count
175+
ProfileCounter EntryCount;
176+
177+
/// The availability used to determine if declarations of this function
178+
/// should use weak linking.
179+
AvailabilityContext Availability;
180+
181+
/// This is the number of uses of this SILFunction inside the SIL.
182+
/// It does not include references from debug scopes.
183+
unsigned RefCount = 0;
184+
163185
/// The function's bare attribute. Bare means that the function is SIL-only
164186
/// and does not require debug info.
165187
unsigned Bare : 1;
@@ -194,39 +216,16 @@ class SILFunction
194216
/// would indicate.
195217
unsigned HasCReferences : 1;
196218

197-
/// Whether cross-module references to this function should use weak linking.
198-
unsigned IsWeakLinked : 1;
219+
/// Whether cross-module references to this function should always use
220+
/// weak linking.
221+
unsigned IsWeakImported : 1;
199222

200223
// Whether the implementation can be dynamically replaced.
201224
unsigned IsDynamicReplaceable : 1;
202225

203-
/// If != OptimizationMode::NotSet, the optimization mode specified with an
204-
/// function attribute.
205-
OptimizationMode OptMode;
206-
207-
/// This is the number of uses of this SILFunction inside the SIL.
208-
/// It does not include references from debug scopes.
209-
unsigned RefCount = 0;
210-
211-
/// The function's set of semantics attributes.
212-
///
213-
/// TODO: Why is this using a std::string? Why don't we use uniqued
214-
/// StringRefs?
215-
llvm::SmallVector<std::string, 1> SemanticsAttrSet;
216-
217-
/// The function's remaining set of specialize attributes.
218-
std::vector<SILSpecializeAttr*> SpecializeAttrSet;
219-
220-
/// The function's effects attribute.
221-
EffectsKind EffectsKindAttr;
222-
223-
/// Has value if there's a profile for this function
224-
/// Contains Function Entry Count
225-
ProfileCounter EntryCount;
226-
227226
/// True if this function is inlined at least once. This means that the
228227
/// debug info keeps a pointer to this function.
229-
bool Inlined = false;
228+
unsigned Inlined : 1;
230229

231230
/// True if this function is a zombie function. This means that the function
232231
/// is dead and not referenced from anywhere inside the SIL. But it is kept
@@ -235,28 +234,35 @@ class SILFunction
235234
/// *) It is a dead method of a class which has higher visibility than the
236235
/// method itself. In this case we need to create a vtable stub for it.
237236
/// *) It is a function referenced by the specialization information.
238-
bool Zombie = false;
237+
unsigned Zombie : 1;
239238

240239
/// True if this function is in Ownership SSA form and thus must pass
241240
/// ownership verification.
242241
///
243242
/// This enables the verifier to easily prove that before the Ownership Model
244243
/// Eliminator runs on a function, we only see a non-semantic-arc world and
245244
/// after the pass runs, we only see a semantic-arc world.
246-
bool HasOwnership = true;
245+
unsigned HasOwnership : 1;
247246

248247
/// Set if the function body was deserialized from canonical SIL. This implies
249248
/// that the function's home module performed SIL diagnostics prior to
250249
/// serialization.
251-
bool WasDeserializedCanonical = false;
250+
unsigned WasDeserializedCanonical : 1;
252251

253252
/// True if this is a reabstraction thunk of escaping function type whose
254253
/// single argument is a potentially non-escaping closure. This is an escape
255254
/// hatch to allow non-escaping functions to be stored or passed as an
256255
/// argument with escaping function type. The thunk argument's function type
257256
/// is not necessarily @noescape. The only relevant aspect of the argument is
258257
/// that it may have unboxed capture (i.e. @inout_aliasable parameters).
259-
bool IsWithoutActuallyEscapingThunk = false;
258+
unsigned IsWithoutActuallyEscapingThunk : 1;
259+
260+
/// If != OptimizationMode::NotSet, the optimization mode specified with an
261+
/// function attribute.
262+
unsigned OptMode : NumOptimizationModeBits;
263+
264+
/// The function's effects attribute.
265+
unsigned EffectsKindAttr : NumEffectsKindBits;
260266

261267
static void
262268
validateSubclassScope(SubclassScope scope, IsThunk_t isThunk,
@@ -575,17 +581,27 @@ class SILFunction
575581
bool hasCReferences() const { return HasCReferences; }
576582
void setHasCReferences(bool value) { HasCReferences = value; }
577583

584+
/// Returns the availability context used to determine if the function's
585+
/// symbol should be weakly referenced across module boundaries.
586+
AvailabilityContext getAvailabilityForLinkage() const {
587+
return Availability;
588+
}
589+
590+
void setAvailabilityForLinkage(AvailabilityContext availability) {
591+
Availability = availability;
592+
}
593+
578594
/// Returns whether this function's symbol must always be weakly referenced
579595
/// across module boundaries.
580-
bool isWeakLinked() const { return IsWeakLinked; }
581-
/// Forces IRGen to treat references to this function as weak across module
582-
/// boundaries (i.e. if it has external linkage).
583-
void setWeakLinked(bool value = true) {
584-
assert(!IsWeakLinked && "already set");
585-
IsWeakLinked = value;
596+
bool isAlwaysWeakImported() const { return IsWeakImported; }
597+
598+
void setAlwaysWeakImported(bool value) {
599+
IsWeakImported = value;
586600
}
587601

588-
/// Returs whether this function implementation can be dynamically replaced.
602+
bool isWeakImported() const;
603+
604+
/// Returns whether this function implementation can be dynamically replaced.
589605
IsDynamicallyReplaceable_t isDynamicallyReplaceable() const {
590606
return IsDynamicallyReplaceable_t(IsDynamicReplaceable);
591607
}
@@ -650,13 +666,17 @@ class SILFunction
650666

651667
/// Get this function's optimization mode or OptimizationMode::NotSet if it is
652668
/// not set for this specific function.
653-
OptimizationMode getOptimizationMode() const { return OptMode; }
669+
OptimizationMode getOptimizationMode() const {
670+
return OptimizationMode(OptMode);
671+
}
654672

655673
/// Returns the optimization mode for the function. If no mode is set for the
656674
/// function, returns the global mode, i.e. the mode of the module's options.
657675
OptimizationMode getEffectiveOptimizationMode() const;
658676

659-
void setOptimizationMode(OptimizationMode mode) { OptMode = mode; }
677+
void setOptimizationMode(OptimizationMode mode) {
678+
OptMode = unsigned(mode);
679+
}
660680

661681
/// \returns True if the function is optimizable (i.e. not marked as no-opt),
662682
/// or is raw SIL (so that the mandatory passes still run).
@@ -726,16 +746,16 @@ class SILFunction
726746
void setInlineStrategy(Inline_t inStr) { InlineStrategy = inStr; }
727747

728748
/// \return the function side effects information.
729-
EffectsKind getEffectsKind() const { return EffectsKindAttr; }
749+
EffectsKind getEffectsKind() const { return EffectsKind(EffectsKindAttr); }
730750

731751
/// \return True if the function is annotated with the @_effects attribute.
732752
bool hasEffectsKind() const {
733-
return EffectsKindAttr != EffectsKind::Unspecified;
753+
return EffectsKind(EffectsKindAttr) != EffectsKind::Unspecified;
734754
}
735755

736756
/// Set the function side effect information.
737757
void setEffectsKind(EffectsKind E) {
738-
EffectsKindAttr = E;
758+
EffectsKindAttr = unsigned(E);
739759
}
740760

741761
/// Get this function's global_init attribute.

include/swift/Serialization/ModuleFormat.h

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5252
/// describe what change you made. The content of this comment isn't important;
5353
/// it just ensures a conflict if two people change the module format.
5454
/// Don't worry about adhering to the 80-column limit for this line.
55-
const uint16_t SWIFTMODULE_VERSION_MINOR = 500; // distinguish implicit raw values for enum cases
55+
const uint16_t SWIFTMODULE_VERSION_MINOR = 501; // SIL function availability
5656

5757
using DeclIDField = BCFixed<31>;
5858

@@ -473,6 +473,44 @@ enum class ImportControl : uint8_t {
473473
};
474474
using ImportControlField = BCFixed<2>;
475475

476+
// Encodes a VersionTuple:
477+
//
478+
// Major
479+
// Minor
480+
// Subminor
481+
// HasMinor
482+
// HasSubminor
483+
#define BC_AVAIL_TUPLE\
484+
BCVBR<5>,\
485+
BCVBR<5>,\
486+
BCVBR<4>,\
487+
BCFixed<1>,\
488+
BCFixed<1>
489+
490+
#define LIST_VER_TUPLE_PIECES(X)\
491+
X##_Major, X##_Minor, X##_Subminor, X##_HasMinor, X##_HasSubminor
492+
#define DEF_VER_TUPLE_PIECES(X) unsigned LIST_VER_TUPLE_PIECES(X)
493+
#define DECODE_VER_TUPLE(X)\
494+
if (X##_HasMinor) {\
495+
if (X##_HasSubminor)\
496+
X = llvm::VersionTuple(X##_Major, X##_Minor, X##_Subminor);\
497+
else\
498+
X = llvm::VersionTuple(X##_Major, X##_Minor);\
499+
}\
500+
else X = llvm::VersionTuple(X##_Major);
501+
#define ENCODE_VER_TUPLE(X, X_Expr)\
502+
unsigned X##_Major = 0, X##_Minor = 0, X##_Subminor = 0,\
503+
X##_HasMinor = 0, X##_HasSubminor = 0;\
504+
const auto &X##_Val = X_Expr;\
505+
if (X##_Val.hasValue()) {\
506+
const auto &Y = X##_Val.getValue();\
507+
X##_Major = Y.getMajor();\
508+
X##_Minor = Y.getMinor().getValueOr(0);\
509+
X##_Subminor = Y.getSubminor().getValueOr(0);\
510+
X##_HasMinor = Y.getMinor().hasValue();\
511+
X##_HasSubminor = Y.getSubminor().hasValue();\
512+
}
513+
476514
/// The various types of blocks that can occur within a serialized Swift
477515
/// module.
478516
///
@@ -1596,20 +1634,6 @@ namespace decls_block {
15961634
BCFixed<2> // optimize value
15971635
>;
15981636

1599-
// Encodes a VersionTuple:
1600-
//
1601-
// Major
1602-
// Minor
1603-
// Subminor
1604-
// HasMinor
1605-
// HasSubminor
1606-
#define BC_AVAIL_TUPLE\
1607-
BCVBR<5>,\
1608-
BCVBR<5>,\
1609-
BCVBR<4>,\
1610-
BCFixed<1>,\
1611-
BCFixed<1>
1612-
16131637
using AvailableDeclAttrLayout = BCRecordLayout<
16141638
Available_DECL_ATTR,
16151639
BCFixed<1>, // implicit flag
@@ -1625,8 +1649,6 @@ namespace decls_block {
16251649
BCBlob // platform, followed by message
16261650
>;
16271651

1628-
#undef BC_AVAIL_TUPLE
1629-
16301652
using ObjCDeclAttrLayout = BCRecordLayout<
16311653
ObjC_DECL_ATTR,
16321654
BCFixed<1>, // implicit flag

0 commit comments

Comments
 (0)