Skip to content

Commit 76d337c

Browse files
authored
Merge pull request #62444 from tshortli/back-deploy-attr-duplicate-symbols-error
SILGen: Fix 'multiple definitions of symbol' error for functions with `@_backDeploy` containing defer blocks
2 parents 86d3220 + 95a9310 commit 76d337c

File tree

5 files changed

+112
-27
lines changed

5 files changed

+112
-27
lines changed

lib/SILGen/SILGen.cpp

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -732,15 +732,16 @@ SILFunction *SILGenModule::getFunction(SILDeclRef constant,
732732

733733
emittedFunctions[constant] = F;
734734

735-
if (!delayedFunctions.count(constant)) {
735+
auto foundDelayed = delayedFunctions.find(constant);
736+
if (foundDelayed == delayedFunctions.end()) {
736737
if (isEmittedOnDemand(M, constant)) {
737-
forcedFunctions.push_back(constant);
738+
if (forcedFunctions.insert(constant).second)
739+
pendingForcedFunctions.push_back(constant);
738740
return F;
739741
}
740742
}
741743

742744
// If we delayed emitting this function previously, we need it now.
743-
auto foundDelayed = delayedFunctions.find(constant);
744745
if (foundDelayed != delayedFunctions.end()) {
745746
// Move the function to its proper place within the module.
746747
M.functions.remove(F);
@@ -752,7 +753,8 @@ SILFunction *SILGenModule::getFunction(SILDeclRef constant,
752753
M.functions.insertAfter(insertAfter->getIterator(), F);
753754
}
754755

755-
forcedFunctions.push_back(constant);
756+
if (forcedFunctions.insert(constant).second)
757+
pendingForcedFunctions.push_back(constant);
756758
delayedFunctions.erase(foundDelayed);
757759
} else {
758760
// We would have registered a delayed function as "last emitted" when we
@@ -770,7 +772,6 @@ bool SILGenModule::hasFunction(SILDeclRef constant) {
770772
void SILGenModule::visitFuncDecl(FuncDecl *fd) { emitFunction(fd); }
771773

772774
void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) {
773-
774775
if (!f->empty()) {
775776
diagnose(constant.getAsRegularLocation(), diag::sil_function_redefinition,
776777
f->getName());
@@ -1150,24 +1151,28 @@ static void emitOrDelayFunction(SILGenModule &SGM, SILDeclRef constant) {
11501151
!constant.isDynamicallyReplaceable() &&
11511152
!isPossiblyUsedExternally(linkage, SGM.M.isWholeModule());
11521153

1153-
// Avoid emitting a delayable definition if it hasn't already been referenced.
1154-
SILFunction *f = nullptr;
1155-
if (mayDelay)
1156-
f = SGM.getEmittedFunction(constant, ForDefinition);
1157-
else
1158-
f = SGM.getFunction(constant, ForDefinition);
1159-
1160-
// If we don't want to emit now, remember how for later.
1161-
if (!f) {
1162-
SGM.delayedFunctions.insert({constant, emitAfter});
1163-
// Even though we didn't emit the function now, update the
1164-
// lastEmittedFunction so that we preserve the original ordering that
1165-
// the symbols would have been emitted in.
1166-
SGM.lastEmittedFunction = constant;
1154+
if (!mayDelay) {
1155+
SGM.emitFunctionDefinition(constant, SGM.getFunction(constant, ForDefinition));
1156+
return;
1157+
}
1158+
1159+
// If the function is already forced then it was previously delayed and then
1160+
// referenced. We don't need to emit or delay it again.
1161+
if (SGM.forcedFunctions.contains(constant))
1162+
return;
1163+
1164+
if (auto *f = SGM.getEmittedFunction(constant, ForDefinition)) {
1165+
SGM.emitFunctionDefinition(constant, f);
11671166
return;
11681167
}
11691168

1170-
SGM.emitFunctionDefinition(constant, f);
1169+
// This is a delayable function so remember how to emit it in case it gets
1170+
// referenced later.
1171+
SGM.delayedFunctions.insert({constant, emitAfter});
1172+
// Even though we didn't emit the function now, update the
1173+
// lastEmittedFunction so that we preserve the original ordering that
1174+
// the symbols would have been emitted in.
1175+
SGM.lastEmittedFunction = constant;
11711176
}
11721177

11731178
void SILGenModule::preEmitFunction(SILDeclRef constant, SILFunction *F,
@@ -2222,13 +2227,13 @@ class SILGenModuleRAII {
22222227
// Emit any delayed definitions that were forced.
22232228
// Emitting these may in turn force more definitions, so we have to take
22242229
// care to keep pumping the queues.
2225-
while (!SGM.forcedFunctions.empty()
2230+
while (!SGM.pendingForcedFunctions.empty()
22262231
|| !SGM.pendingConformances.empty()) {
2227-
while (!SGM.forcedFunctions.empty()) {
2228-
auto &front = SGM.forcedFunctions.front();
2232+
while (!SGM.pendingForcedFunctions.empty()) {
2233+
auto &front = SGM.pendingForcedFunctions.front();
22292234
SGM.emitFunctionDefinition(
22302235
front, SGM.getEmittedFunction(front, ForDefinition));
2231-
SGM.forcedFunctions.pop_front();
2236+
SGM.pendingForcedFunctions.pop_front();
22322237
}
22332238
while (!SGM.pendingConformances.empty()) {
22342239
SGM.getWitnessTable(SGM.pendingConformances.front());

lib/SILGen/SILGen.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
6666
llvm::DenseMap<SILDeclRef, SILDeclRef> delayedFunctions;
6767

6868
/// Queue of delayed SILFunctions that need to be forced.
69-
std::deque<SILDeclRef> forcedFunctions;
69+
std::deque<SILDeclRef> pendingForcedFunctions;
70+
71+
/// Delayed SILFunctions that need to be forced.
72+
llvm::DenseSet<SILDeclRef> forcedFunctions;
7073

7174
/// Mapping global VarDecls to their onceToken and onceFunc, respectively.
7275
llvm::DenseMap<VarDecl *, std::pair<SILGlobalVariable *,
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// RUN: %target-swift-emit-sil -parse-as-library -module-name back_deploy %s -target %target-cpu-apple-macosx10.50 -verify
2+
// RUN: %target-swift-emit-silgen -parse-as-library -module-name back_deploy %s | %FileCheck %s
3+
// RUN: %target-swift-emit-silgen -parse-as-library -module-name back_deploy %s -target %target-cpu-apple-macosx10.50 | %FileCheck %s
4+
// RUN: %target-swift-emit-silgen -parse-as-library -module-name back_deploy %s -target %target-cpu-apple-macosx10.60 | %FileCheck %s
5+
6+
// REQUIRES: OS=macosx
7+
// REQUIRES: concurrency
8+
9+
@available(macOS 10.51, *)
10+
@usableFromInline func otherFunc() async {}
11+
12+
// -- Fallback definition of asyncFunc()
13+
// CHECK: sil non_abi [serialized] [ossa] @$s11back_deploy9asyncFuncyyYaFTwB : $@convention(thin) @async () -> ()
14+
// CHECK: bb0:
15+
// CHECK: [[FNREF:%.*]] = function_ref @$s11back_deploy9otherFuncyyYaF : $@convention(thin) @async () -> ()
16+
// CHECK: [[APPLY:%.*]] = apply [[FNREF]]() : $@convention(thin) @async () -> ()
17+
// CHECK: [[RESULT:%.*]] = tuple ()
18+
// CHECK: return [[RESULT]] : $()
19+
20+
// -- Back deployment thunk for trivialFunc()
21+
// CHECK-LABEL: sil non_abi [serialized] [thunk] [ossa] @$s11back_deploy9asyncFuncyyYaFTwb : $@convention(thin) @async () -> ()
22+
// CHECK: bb0:
23+
// CHECK: [[MAJOR:%.*]] = integer_literal $Builtin.Word, 10
24+
// CHECK: [[MINOR:%.*]] = integer_literal $Builtin.Word, 52
25+
// CHECK: [[PATCH:%.*]] = integer_literal $Builtin.Word, 0
26+
// CHECK: [[OSVFN:%.*]] = function_ref @$ss26_stdlib_isOSVersionAtLeastyBi1_Bw_BwBwtF : $@convention(thin) (Builtin.Word, Builtin.Word, Builtin.Word) -> Builtin.Int1
27+
// CHECK: [[AVAIL:%.*]] = apply [[OSVFN]]([[MAJOR]], [[MINOR]], [[PATCH]]) : $@convention(thin) (Builtin.Word, Builtin.Word, Builtin.Word) -> Builtin.Int1
28+
// CHECK: cond_br [[AVAIL]], [[AVAIL_BB:bb[0-9]+]], [[UNAVAIL_BB:bb[0-9]+]]
29+
//
30+
// CHECK: [[UNAVAIL_BB]]:
31+
// CHECK: [[FALLBACKFN:%.*]] = function_ref @$s11back_deploy9asyncFuncyyYaFTwB : $@convention(thin) @async () -> ()
32+
// CHECK: {{%.*}} = apply [[FALLBACKFN]]() : $@convention(thin) @async () -> ()
33+
// CHECK: br [[RETURN_BB:bb[0-9]+]]
34+
//
35+
// CHECK: [[AVAIL_BB]]:
36+
// CHECK: [[ORIGFN:%.*]] = function_ref @$s11back_deploy9asyncFuncyyYaF : $@convention(thin) @async () -> ()
37+
// CHECK: {{%.*}} = apply [[ORIGFN]]() : $@convention(thin) @async () -> ()
38+
// CHECK: br [[RETURN_BB]]
39+
//
40+
// CHECK: [[RETURN_BB]]
41+
// CHECK: [[RESULT:%.*]] = tuple ()
42+
// CHECK: return [[RESULT]] : $()
43+
44+
// -- Original definition of trivialFunc()
45+
// CHECK-LABEL: sil [available 10.52] [ossa] @$s11back_deploy9asyncFuncyyYaF : $@convention(thin) @async () -> ()
46+
@available(macOS 10.51, *)
47+
@_backDeploy(before: macOS 10.52)
48+
public func asyncFunc() async {
49+
await otherFunc()
50+
}
51+
52+
// CHECK-LABEL: sil hidden [available 10.51] [ossa] @$s11back_deploy6calleryyYaF : $@convention(thin) @async () -> ()
53+
@available(macOS 10.51, *)
54+
func caller() async {
55+
// -- Verify the thunk is called
56+
// CHECK: {{%.*}} = function_ref @$s11back_deploy9asyncFuncyyYaFTwb : $@convention(thin) @async () -> ()
57+
await asyncFunc()
58+
}
59+

test/attr/Inputs/BackDeployHelper.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,13 @@ extension IntArray {
151151
public var rawValues: [Int] {
152152
_read { yield _values }
153153
}
154+
155+
@available(BackDeploy 1.0, *)
156+
@_backDeploy(before: BackDeploy 2.0)
157+
public mutating func removeLast() -> Int? {
158+
defer { _values.removeLast() }
159+
return _values.last
160+
}
154161
}
155162

156163
extension ReferenceIntArray {
@@ -192,6 +199,13 @@ extension ReferenceIntArray {
192199
public final var rawValues: [Int] {
193200
_read { yield _values }
194201
}
202+
203+
@available(BackDeploy 1.0, *)
204+
@_backDeploy(before: BackDeploy 2.0)
205+
public final func removeLast() -> Int? {
206+
defer { _values.removeLast() }
207+
return _values.last
208+
}
195209
}
196210

197211
extension Array {

test/attr/attr_backDeploy_evolution.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,9 @@ do {
162162

163163
// CHECK-ABI: library: [5, 43, 3]
164164
// CHECK-BD: client: [5, 43, 3]
165-
print(array.rawValues.print())
165+
array.rawValues.print()
166+
167+
precondition(array.removeLast() == 3)
166168
}
167169

168170
do {
@@ -194,5 +196,7 @@ do {
194196

195197
// CHECK-ABI: library: [7, 40, 1]
196198
// CHECK-BD: client: [7, 40, 1]
197-
print(array.rawValues.print())
199+
array.rawValues.print()
200+
201+
precondition(array.removeLast() == 1)
198202
}

0 commit comments

Comments
 (0)