37
37
#include " swift/SILOptimizer/Utils/PrunedLiveness.h"
38
38
#include " swift/Demangling/Demangler.h"
39
39
#include " llvm/Support/Debug.h"
40
+ #include " clang/AST/DeclObjC.h"
40
41
41
42
using namespace swift ;
42
43
@@ -51,7 +52,7 @@ class DiagnoseLifetimeIssues {
51
52
52
53
bool computeCanonicalLiveness (SILValue def);
53
54
54
- bool isDeadStore (StoreWeakInst *store );
55
+ void reportDeadStore (SILInstruction *storeInst, SILValue src );
55
56
56
57
public:
57
58
DiagnoseLifetimeIssues () {}
@@ -96,7 +97,8 @@ bool DiagnoseLifetimeIssues::computeCanonicalLiveness(SILValue def) {
96
97
auto *user = use->getUser ();
97
98
98
99
// Recurse through copies and enums.
99
- if (isa<CopyValueInst>(user) || isa<EnumInst>(user)) {
100
+ if (isa<CopyValueInst>(user) || isa<EnumInst>(user) ||
101
+ isa<InitExistentialRefInst>(user)) {
100
102
defUseWorklist.insert (cast<SingleValueInstruction>(user));
101
103
continue ;
102
104
}
@@ -156,25 +158,30 @@ static SILValue getCanonicalDef(SILValue val) {
156
158
continue ;
157
159
}
158
160
}
161
+ if (auto *initExRef = dyn_cast<InitExistentialRefInst>(val)) {
162
+ val = initExRef->getOperand ();
163
+ continue ;
164
+ }
159
165
return val;
160
166
}
161
167
}
162
168
163
- // / Returns true if the stored object of \p store is never loaded within the
164
- // / lifetime of the stored object.
165
- bool DiagnoseLifetimeIssues::isDeadStore (StoreWeakInst *store) {
166
- SILValue storedDef = getCanonicalDef (store->getSrc ());
169
+ // / Reports a warning if the stored object \p storedObj is never loaded within
170
+ // / the lifetime of the stored object.
171
+ void DiagnoseLifetimeIssues::reportDeadStore (SILInstruction *storeInst,
172
+ SILValue storedObj) {
173
+ SILValue storedDef = getCanonicalDef (storedObj);
167
174
168
175
// Only for allocations we know that a destroy will actually deallocate the
169
176
// object. Otherwise the object could be kept alive by other references and
170
177
// we would issue a false alarm.
171
178
if (!isAllocation (storedDef))
172
- return false ;
179
+ return ;
173
180
181
+ liveness.clear ();
174
182
liveness.initializeDefBlock (storedDef->getParentBlock ());
175
183
if (!computeCanonicalLiveness (storedDef))
176
- return false ;
177
-
184
+ return ;
178
185
179
186
// Check if the lifetime of the stored object ends at the store_weak.
180
187
//
@@ -186,35 +193,68 @@ bool DiagnoseLifetimeIssues::isDeadStore(StoreWeakInst *store) {
186
193
// always see a potential load if the lifetime of the object goes beyond the
187
194
// store_weak.
188
195
189
- SILBasicBlock *storeBlock = store ->getParent ();
196
+ SILBasicBlock *storeBlock = storeInst ->getParent ();
190
197
if (liveness.getBlockLiveness (storeBlock) != PrunedLiveBlocks::LiveWithin)
191
- return false ;
198
+ return ;
192
199
193
200
// If there are any uses after the store_weak, it means that the liferange of
194
201
// the object goes beyond the store_weak.
195
- for (SILInstruction &inst : make_range (std::next (store ->getIterator ()),
202
+ for (SILInstruction &inst : make_range (std::next (storeInst ->getIterator ()),
196
203
storeBlock->end ())) {
197
204
switch (liveness.isInterestingUser (&inst)) {
198
205
case PrunedLiveness::NonUser:
199
206
break ;
200
207
case PrunedLiveness::NonLifetimeEndingUse:
201
208
case PrunedLiveness::LifetimeEndingUse:
202
- return false ;
209
+ return ;
203
210
}
204
211
}
205
- return true ;
212
+
213
+ // Issue the warning.
214
+ storeInst->getModule ().getASTContext ().Diags .diagnose (
215
+ storeInst->getLoc ().getSourceLoc (), diag::warn_dead_weak_store);
216
+ }
217
+
218
+ // / Returns true if \p inst is a call of an ObjC setter to a weak property.
219
+ static bool isStoreObjcWeak (SILInstruction *inst) {
220
+ auto *apply = dyn_cast<ApplyInst>(inst);
221
+ if (!apply || apply->getNumArguments () < 1 )
222
+ return false ;
223
+
224
+ auto *method = dyn_cast<ObjCMethodInst>(apply->getCallee ());
225
+ if (!method)
226
+ return false ;
227
+
228
+ Decl *decl = method->getMember ().getDecl ();
229
+ auto *accessor = dyn_cast<AccessorDecl>(decl);
230
+ if (!accessor)
231
+ return false ;
232
+
233
+ auto *var = dyn_cast<VarDecl>(accessor->getStorage ());
234
+ if (!var)
235
+ return false ;
236
+
237
+ ClangNode clangNode = var->getClangNode ();
238
+ if (!clangNode)
239
+ return false ;
240
+
241
+ auto *objcDecl = dyn_cast_or_null<clang::ObjCPropertyDecl>(clangNode.getAsDecl ());
242
+ if (!objcDecl)
243
+ return false ;
244
+
245
+ return objcDecl->getSetterKind () == clang::ObjCPropertyDecl::Weak;
206
246
}
207
247
208
248
// / Prints warnings for dead weak stores in \p function.
209
249
void DiagnoseLifetimeIssues::diagnose (SILFunction *function) {
210
250
for (SILBasicBlock &block : *function) {
211
251
for (SILInstruction &inst : block) {
212
252
if (auto *stWeak = dyn_cast<StoreWeakInst>(&inst)) {
213
- if ( isDeadStore ( stWeak)) {
214
- function-> getModule (). getASTContext (). Diags . diagnose (
215
- stWeak-> getLoc (). getSourceLoc (), diag::warn_dead_weak_store);
216
- }
217
- liveness. clear ( );
253
+ reportDeadStore ( stWeak, stWeak-> getSrc ());
254
+ continue ;
255
+ }
256
+ if ( isStoreObjcWeak (&inst)) {
257
+ reportDeadStore (&inst, cast<ApplyInst>(&inst)-> getArgument ( 0 ) );
218
258
continue ;
219
259
}
220
260
}
0 commit comments