Skip to content

Commit 35acc0f

Browse files
committed
[DI] Given x' = load x; (apply (class_method x') x'), check the apply for DI violations, not class_method.
This is working around an additional use-list DI ordering issue that I exposed when implementing High Level Memory Operations. Specifically, DI started to error on: (class_method x) instead of on: (apply (class_method x) x) We would also try to emit an error on the apply, but we would squelch the apply error (which is more accuracte) since we had already emitted the class_method error. This commit conservatively checks for this condition and skips the class method so we can emit the more descriptive error on the apply.
1 parent 8d4aac4 commit 35acc0f

File tree

1 file changed

+37
-4
lines changed

1 file changed

+37
-4
lines changed

lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,6 +1157,27 @@ static bool isSelfInitUse(SILArgument *Arg) {
11571157
return isSelfInitUse(Pred->getTerminator());
11581158
}
11591159

1160+
/// Returns true if \p Method is a callee of a full apply site that takes in \p
1161+
/// Pointer as an argument. In such a case, we want to ignore the class method
1162+
/// use and allow for the use by the apply inst to take precedence.
1163+
static bool shouldIgnoreClassMethodUseError(
1164+
ClassMethodInst *Method, SILValue Pointer) {
1165+
1166+
// In order to work around use-list ordering issues, if this method is called
1167+
// by an apply site that has I as an argument, we want to process the apply
1168+
// site for errors to emit, not the class method. If we do not obey these
1169+
// conditions, then continue to treat the class method as an escape.
1170+
auto CheckFullApplySite = [&](Operand *Op) -> bool {
1171+
FullApplySite FAS(Op->getUser());
1172+
if (!FAS || (FAS.getCallee() != Method))
1173+
return false;
1174+
return llvm::any_of(
1175+
FAS.getArgumentsWithoutIndirectResults(),
1176+
[&](SILValue Arg) -> bool { return Arg == Pointer; });
1177+
};
1178+
1179+
return llvm::any_of(Method->getUses(), CheckFullApplySite);
1180+
}
11601181

11611182
void ElementUseCollector::
11621183
collectClassSelfUses(SILValue ClassPointer, SILType MemorySILType,
@@ -1197,6 +1218,12 @@ collectClassSelfUses(SILValue ClassPointer, SILType MemorySILType,
11971218
continue;
11981219
}
11991220

1221+
if (auto *Method = dyn_cast<ClassMethodInst>(User)) {
1222+
if (shouldIgnoreClassMethodUseError(Method, ClassPointer)){
1223+
continue;
1224+
}
1225+
}
1226+
12001227
// If this is an upcast instruction, it is a conversion of self to the base.
12011228
// This is either part of a super.init sequence, or a general superclass
12021229
// access.
@@ -1324,23 +1351,29 @@ void ElementUseCollector::collectDelegatingClassInitSelfUses() {
13241351
continue;
13251352
}
13261353

1327-
// class_method that refers to an initializing constructor is a method
1328-
// lookup for delegation, which is ignored.
1329-
if (auto Method = dyn_cast<ClassMethodInst>(User)) {
1354+
if (auto *Method = dyn_cast<ClassMethodInst>(User)) {
1355+
// class_method that refers to an initializing constructor is a method
1356+
// lookup for delegation, which is ignored.
13301357
if (Method->getMember().kind == SILDeclRef::Kind::Initializer)
13311358
continue;
1359+
1360+
/// Returns true if \p Method used by an apply in a way that we know
1361+
/// will cause us to emit a better error.
1362+
if (shouldIgnoreClassMethodUseError(Method, LI))
1363+
continue;
13321364
}
13331365

13341366
// If this is an upcast instruction, it is a conversion of self to the
13351367
// base. This is either part of a super.init sequence, or a general
13361368
// superclass access. We special case super.init calls since they are
13371369
// part of the object lifecycle.
1338-
if (auto *UCI = dyn_cast<UpcastInst>(User))
1370+
if (auto *UCI = dyn_cast<UpcastInst>(User)) {
13391371
if (auto *subAI = isSuperInitUse(UCI)) {
13401372
Uses.push_back(DIMemoryUse(subAI, DIUseKind::SuperInit, 0, 1));
13411373
recordFailableInitCall(subAI);
13421374
continue;
13431375
}
1376+
}
13441377

13451378
// We only track two kinds of uses for delegating initializers:
13461379
// calls to self.init, and "other", which we choose to model as escapes.

0 commit comments

Comments
 (0)