Skip to content

Commit 619673e

Browse files
Merge pull request #20570 from aschwaighofer/synthesize_accessors_dynamic_globals
Synthesize accessors for dynamic global variables
2 parents 2dde40f + 40f0c43 commit 619673e

18 files changed

+68
-26
lines changed

include/swift/AST/Decl.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,7 @@ class alignas(1 << DeclAlignInBits) Decl {
570570
HasAnyUnavailableValues : 1
571571
);
572572

573-
SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1,
573+
SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1,
574574
/// If the module was or is being compiled with `-enable-testing`.
575575
TestingEnabled : 1,
576576

@@ -586,7 +586,10 @@ class alignas(1 << DeclAlignInBits) Decl {
586586
HasResolvedImports : 1,
587587

588588
// If the module was or is being compiled with `-enable-private-imports`.
589-
PrivateImportsEnabled : 1
589+
PrivateImportsEnabled : 1,
590+
591+
// If the module is compiled with `-enable-implicit-dynamic`.
592+
ImplicitDynamicEnabled : 1
590593
);
591594

592595
SWIFT_INLINE_BITFIELD(PrecedenceGroupDecl, Decl, 1+2,
@@ -2594,6 +2597,10 @@ class ValueDecl : public Decl {
25942597
return isObjC() && isDynamic();
25952598
}
25962599

2600+
bool isNativeDynamic() const {
2601+
return !isObjC() && isDynamic();
2602+
}
2603+
25972604
/// Set whether this type is 'dynamic' or not.
25982605
void setIsDynamic(bool value);
25992606

include/swift/AST/Module.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,14 @@ class ModuleDecl : public DeclContext, public TypeDecl {
283283
Bits.ModuleDecl.TestingEnabled = enabled;
284284
}
285285

286+
// Returns true if this module is compiled with implicit dynamic.
287+
bool isImplicitDynamicEnabled() const {
288+
return Bits.ModuleDecl.ImplicitDynamicEnabled;
289+
}
290+
void setImplicitDynamicEnabled(bool enabled = true) {
291+
Bits.ModuleDecl.ImplicitDynamicEnabled = enabled;
292+
}
293+
286294
/// Returns true if this module was or is begin compile with
287295
/// `-enable-private-imports`.
288296
bool arePrivateImportsEnabled() const {

include/swift/Basic/LangOptions.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,6 @@ namespace swift {
144144
/// was not compiled with -enable-testing.
145145
bool EnableTestableAttrRequiresTestableModule = true;
146146

147-
/// If true, the 'dynamic' attribute is added to all applicable
148-
/// declarations.
149-
bool EnableImplicitDynamic = false;
150-
151147
///
152148
/// Flags for developers
153149
///

include/swift/Frontend/FrontendOptions.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,12 @@ class FrontendOptions {
198198
/// \see ModuleDecl::arePrivateImportsEnabled
199199
bool EnablePrivateImports = false;
200200

201+
202+
/// Indicates whether we add implicit dynamic.
203+
///
204+
/// \see ModuleDecl::isImplicitDynamicEnabled
205+
bool EnableImplicitDynamic = false;
206+
201207
/// Enables the "fully resilient" resilience strategy.
202208
///
203209
/// \see ResilienceStrategy::Resilient

lib/AST/ASTVerifier.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3149,12 +3149,12 @@ class Verifier : public ASTWalker {
31493149
storageDecl->getWriteImpl() ==
31503150
WriteImplKind::StoredWithObservers ||
31513151
storageDecl->getWriteImpl() == WriteImplKind::MutableAddress) &&
3152-
storageDecl->isDynamic() && !storageDecl->isObjC()) &&
3152+
storageDecl->isNativeDynamic()) &&
31533153
// We allow a non dynamic getter if there is a dynamic read.
31543154
!(FD->isGetter() &&
31553155
(storageDecl->getReadImpl() == ReadImplKind::Read ||
31563156
storageDecl->getReadImpl() == ReadImplKind::Address) &&
3157-
storageDecl->isDynamic() && !storageDecl->isObjC())) {
3157+
storageDecl->isNativeDynamic())) {
31583158
Out << "Property and accessor do not match for 'dynamic'\n";
31593159
abort();
31603160
}

lib/AST/Decl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,7 +1549,7 @@ getDirectReadWriteAccessStrategy(const AbstractStorageDecl *storage) {
15491549
return AccessStrategy::getStorage();
15501550
case ReadWriteImplKind::Stored: {
15511551
// If the storage isDynamic (and not @objc) use the accessors.
1552-
if (storage->isDynamic() && !storage->isObjC())
1552+
if (storage->isNativeDynamic())
15531553
return AccessStrategy::getMaterializeToTemporary(
15541554
getOpaqueReadAccessStrategy(storage, false),
15551555
getOpaqueWriteAccessStrategy(storage, false));
@@ -1623,7 +1623,7 @@ AbstractStorageDecl::getAccessStrategy(AccessSemantics semantics,
16231623
if (isPolymorphic(this))
16241624
return getOpaqueAccessStrategy(this, accessKind, /*dispatch*/ true);
16251625

1626-
if (isDynamic())
1626+
if (isNativeDynamic())
16271627
return getOpaqueAccessStrategy(this, accessKind, /*dispatch*/ false);
16281628

16291629
// If the storage is resilient to the given use DC (perhaps because

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ bool ArgsToFrontendOptionsConverter::convert(
6969
Opts.EnableTesting |= Args.hasArg(OPT_enable_testing);
7070
Opts.EnablePrivateImports |= Args.hasArg(OPT_enable_private_imports);
7171
Opts.EnableResilience |= Args.hasArg(OPT_enable_resilience);
72+
Opts.EnableImplicitDynamic |= Args.hasArg(OPT_enable_implicit_dynamic);
7273

7374
Opts.TrackSystemDeps |= Args.hasArg(OPT_track_system_dependencies);
7475

lib/Frontend/CompilerInvocation.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,6 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
274274
Opts.DebugConstraintSolver |= Args.hasArg(OPT_debug_constraints);
275275
Opts.NamedLazyMemberLoading &= !Args.hasArg(OPT_disable_named_lazy_member_loading);
276276
Opts.DebugGenericSignatures |= Args.hasArg(OPT_debug_generic_signatures);
277-
Opts.EnableImplicitDynamic |= Args.hasArg(OPT_enable_implicit_dynamic);
278277

279278
if (Args.hasArg(OPT_verify_syntax_tree)) {
280279
Opts.BuildSyntaxTree = true;

lib/Frontend/Frontend.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,8 @@ ModuleDecl *CompilerInstance::getMainModule() {
488488
MainModule->setTestingEnabled();
489489
if (Invocation.getFrontendOptions().EnablePrivateImports)
490490
MainModule->setPrivateImportsEnabled();
491+
if (Invocation.getFrontendOptions().EnableImplicitDynamic)
492+
MainModule->setImplicitDynamicEnabled();
491493

492494
if (Invocation.getFrontendOptions().EnableResilience)
493495
MainModule->setResilienceStrategy(ResilienceStrategy::Resilient);

lib/SIL/SILDeclRef.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -964,13 +964,14 @@ bool SILDeclRef::isDynamicallyReplaceable() const {
964964
return false;
965965

966966
if (kind == SILDeclRef::Kind::Destroyer ||
967-
kind == SILDeclRef::Kind::Initializer) {
967+
kind == SILDeclRef::Kind::Initializer ||
968+
kind == SILDeclRef::Kind::GlobalAccessor) {
968969
return false;
969970
}
970971

971972
if (!hasDecl())
972973
return false;
973974

974975
auto decl = getDecl();
975-
return decl->isDynamic() && !decl->isObjC();
976+
return decl->isNativeDynamic();
976977
}

lib/Sema/CodeSynthesis.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2042,6 +2042,11 @@ void swift::maybeAddAccessorsToStorage(TypeChecker &TC,
20422042
return;
20432043

20442044
if (!dc->isTypeContext()) {
2045+
// dynamic globals need accessors.
2046+
if (dc->isModuleScopeContext() && storage->isNativeDynamic()) {
2047+
addTrivialAccessorsToStorage(storage, TC);
2048+
return;
2049+
}
20452050
// Fixed-layout global variables don't get accessors.
20462051
if (!storage->isResilient())
20472052
return;

lib/Sema/TypeCheckAttr.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2175,7 +2175,7 @@ void TypeChecker::checkDynamicReplacementAttribute(ValueDecl *D) {
21752175
return;
21762176
}
21772177

2178-
if (D->isDynamic() && !D->isObjC()) {
2178+
if (D->isNativeDynamic()) {
21792179
diagnose(attr->getLocation(), diag::dynamic_replacement_must_not_be_dynamic,
21802180
D->getBaseName());
21812181
attr->setInvalid();
@@ -2451,9 +2451,6 @@ TypeChecker::diagnosticIfDeclCannotBePotentiallyUnavailable(const Decl *D) {
24512451
}
24522452

24532453
void TypeChecker::addImplicitDynamicAttribute(Decl *D) {
2454-
if (!getLangOpts().EnableImplicitDynamic)
2455-
return;
2456-
24572454
// Add the attribute if the decl kind allows it and it is not an accessor
24582455
// decl. Accessor decls should always infer the var/subscript's attribute.
24592456
if (!DeclAttribute::canAttributeAppearOnDecl(DAK_Dynamic, D) ||

lib/Sema/TypeCheckDecl.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,6 +1214,11 @@ IsDynamicRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
12141214
if (!DeclAttribute::canAttributeAppearOnDecl(DAK_Dynamic, decl))
12151215
return false;
12161216

1217+
// Add dynamic if -enable-implicit-dynamic was requested.
1218+
if (decl->getModuleContext()->isImplicitDynamicEnabled()) {
1219+
TypeChecker::addImplicitDynamicAttribute(decl);
1220+
}
1221+
12171222
// If 'dynamic' was explicitly specified, check it.
12181223
if (decl->getAttrs().hasAttribute<DynamicAttr>()) {
12191224
if (decl->getASTContext().LangOpts.isSwiftVersionAtLeast(5))
@@ -2726,8 +2731,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
27262731
}
27272732

27282733
void visitSubscriptDecl(SubscriptDecl *SD) {
2729-
TC.addImplicitDynamicAttribute(SD);
2730-
27312734
TC.validateDecl(SD);
27322735

27332736
if (!SD->isInvalid()) {
@@ -3197,8 +3200,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
31973200
}
31983201

31993202
void visitVarDecl(VarDecl *VD) {
3200-
TC.addImplicitDynamicAttribute(VD);
3201-
32023203
// Delay type-checking on VarDecls until we see the corresponding
32033204
// PatternBindingDecl.
32043205

@@ -3250,8 +3251,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
32503251
}
32513252

32523253
void visitFuncDecl(FuncDecl *FD) {
3253-
TC.addImplicitDynamicAttribute(FD);
3254-
32553254
TC.validateDecl(FD);
32563255

32573256
if (!FD->isInvalid()) {
@@ -3368,7 +3367,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
33683367
}
33693368

33703369
void visitConstructorDecl(ConstructorDecl *CD) {
3371-
TC.addImplicitDynamicAttribute(CD);
33723370
TC.validateDecl(CD);
33733371

33743372
if (!CD->isInvalid()) {

lib/Sema/TypeChecker.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1095,7 +1095,7 @@ class TypeChecker final : public LazyResolver {
10951095
void typeCheckDecl(Decl *D);
10961096

10971097
void checkDeclAttributesEarly(Decl *D);
1098-
void addImplicitDynamicAttribute(Decl *D);
1098+
static void addImplicitDynamicAttribute(Decl *D);
10991099
void checkDeclAttributes(Decl *D);
11001100
void checkDynamicReplacementAttribute(ValueDecl *D);
11011101
void checkTypeModifyingDeclAttributes(VarDecl *var);

lib/TBDGen/TBDGen.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ void TBDGenVisitor::visitAbstractFunctionDecl(AbstractFunctionDecl *AFD) {
165165
addSymbol(SILDeclRef(AFD));
166166

167167
// Add the global function pointer for a dynamically replaceable function.
168-
if (AFD->isDynamic() && ! AFD->isObjC()) {
168+
if (AFD->isNativeDynamic()) {
169169
addSymbol(LinkEntity::forDynamicallyReplaceableFunctionVariable(AFD));
170170
addSymbol(LinkEntity::forDynamicallyReplaceableFunctionImpl(AFD));
171171
addSymbol(LinkEntity::forDynamicallyReplaceableFunctionKey(AFD));

test/Interpreter/Inputs/dynamic_replacement_module.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#if MODULE
2+
public dynamic var public_global_var = "public_global_var"
3+
24
public dynamic func public_global_func() -> String {
35
return "public_global_func"
46
}
@@ -64,6 +66,8 @@ public enum PublicEnumeration<Q> {
6466
}
6567
}
6668
#elseif MODULENODYNAMIC
69+
public var public_global_var = "public_global_var"
70+
6771
public func public_global_func() -> String {
6872
return "public_global_func"
6973
}
@@ -134,6 +138,11 @@ import Module1
134138

135139
/// Public global functions, struct, class, and enum.
136140

141+
@_dynamicReplacement(for: public_global_var)
142+
public var replacement_for_public_global_var : String {
143+
return "replacement of public_global_var"
144+
}
145+
137146
@_dynamicReplacement(for: public_global_func())
138147
public func replacement_for_public_global_func() -> String {
139148
return "replacement of " + public_global_func()

test/Interpreter/dynamic_replacement.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ func expectedResult(_ forOriginalLibrary: Bool, _ expectedOriginalString: Strin
7272
}
7373

7474
func checkExpectedResults(forOriginalLibrary useOrig: Bool) {
75+
expectTrue(public_global_var == expectedResult(useOrig, "public_global_var"))
76+
7577
expectTrue(public_global_func() ==
7678
expectedResult(useOrig, "public_global_func"))
7779
expectTrue(public_global_generic_func(Int.self) ==

test/SILGen/dynamically_replaceable.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,3 +271,14 @@ extension GenericS {
271271
}
272272
}
273273
}
274+
275+
dynamic var globalX = 0
276+
// CHECK-LABEL: sil hidden [dynamically_replacable] @$s23dynamically_replaceable7globalXSivg : $@convention(thin) () -> Int
277+
// CHECK-LABEL: sil hidden [dynamically_replacable] @$s23dynamically_replaceable7globalXSivs : $@convention(thin) (Int) -> ()
278+
// CHECK-LABEL: sil hidden @$s23dynamically_replaceable7getsetXyS2iF
279+
// CHECK: dynamic_function_ref @$s23dynamically_replaceable7globalXSivs
280+
// CHECK: dynamic_function_ref @$s23dynamically_replaceable7globalXSivg
281+
func getsetX(_ x: Int) -> Int {
282+
globalX = x
283+
return globalX
284+
}

0 commit comments

Comments
 (0)