Skip to content

Commit ef69fdb

Browse files
committed
[Coverage] Visit the PatternBindingDecl in a ForEachStmt
This fixes a crash which occurs because there is no mapping region associated with non-static initializers in the loop's iterator.
1 parent c68f363 commit ef69fdb

File tree

2 files changed

+35
-19
lines changed

2 files changed

+35
-19
lines changed

lib/SILGen/SILGenProfiling.cpp

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,30 @@ static bool isUnmappedDecl(Decl *D) {
3636
return D->isImplicit() || isa<EnumCaseDecl>(D);
3737
}
3838

39+
/// Walk the non-static initializers in \p PBD.
40+
static void walkForProfiling(PatternBindingDecl *PBD, ASTWalker &Walker) {
41+
if (PBD && !PBD->isStatic())
42+
for (auto E : PBD->getPatternList())
43+
if (E.getInit())
44+
E.getInit()->walk(Walker);
45+
}
46+
47+
/// Walk the AST of \c Root and related nodes that are relevant for profiling.
48+
static void walkForProfiling(AbstractFunctionDecl *Root, ASTWalker &Walker) {
49+
Root->walk(Walker);
50+
51+
// We treat class initializers as part of the constructor for profiling.
52+
if (auto *CD = dyn_cast<ConstructorDecl>(Root)) {
53+
Type DT = CD->getDeclContext()->getDeclaredTypeInContext();
54+
auto *NominalType = DT->getNominalOrBoundGenericNominal();
55+
for (auto *Member : NominalType->getMembers()) {
56+
// Find pattern binding declarations that have initializers.
57+
if (auto *PBD = dyn_cast<PatternBindingDecl>(Member))
58+
walkForProfiling(PBD, Walker);
59+
}
60+
}
61+
}
62+
3963
ProfilerRAII::ProfilerRAII(SILGenModule &SGM, AbstractFunctionDecl *D)
4064
: SGM(SGM), PreviousProfiler(std::move(SGM.Profiler)) {
4165
const auto &Opts = SGM.M.getOptions();
@@ -82,6 +106,7 @@ struct MapRegionCounters : public ASTWalker {
82106
CounterMap[FS->getBody()] = NextCounter++;
83107
} else if (auto *FES = dyn_cast<ForEachStmt>(S)) {
84108
CounterMap[FES->getBody()] = NextCounter++;
109+
walkForProfiling(FES->getIterator(), *this);
85110
} else if (auto *SS = dyn_cast<SwitchStmt>(S)) {
86111
CounterMap[SS] = NextCounter++;
87112
} else if (auto *CS = dyn_cast<CaseStmt>(S)) {
@@ -494,6 +519,7 @@ struct CoverageMapping : public ASTWalker {
494519
} else if (auto *FES = dyn_cast<ForEachStmt>(S)) {
495520
assignCounter(FES, CounterExpr::Zero());
496521
assignCounter(FES->getBody());
522+
walkForProfiling(FES->getIterator(), *this);
497523

498524
} else if (auto *SS = dyn_cast<SwitchStmt>(S)) {
499525
assignCounter(SS);
@@ -625,25 +651,6 @@ struct CoverageMapping : public ASTWalker {
625651

626652
} // end anonymous namespace
627653

628-
/// Walk the AST of \c Root and related nodes that are relevant for profiling.
629-
static void walkForProfiling(AbstractFunctionDecl *Root, ASTWalker &Walker) {
630-
Root->walk(Walker);
631-
632-
// We treat class initializers as part of the constructor for profiling.
633-
if (auto *CD = dyn_cast<ConstructorDecl>(Root)) {
634-
Type DT = CD->getDeclContext()->getDeclaredTypeInContext();
635-
auto *NominalType = DT->getNominalOrBoundGenericNominal();
636-
for (auto *Member : NominalType->getMembers()) {
637-
// Find pattern binding declarations that have initializers.
638-
if (auto *PBD = dyn_cast<PatternBindingDecl>(Member))
639-
if (!PBD->isStatic())
640-
for (auto E : PBD->getPatternList())
641-
if (E.getInit())
642-
E.getInit()->walk(Walker);
643-
}
644-
}
645-
}
646-
647654
static llvm::GlobalValue::LinkageTypes
648655
getEquivalentPGOLinkage(FormalLinkage Linkage) {
649656
switch (Linkage) {

test/SILGen/coverage_closures.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -profile-generate -profile-coverage-mapping -emit-sorted-sil -emit-sil -module-name coverage_closures %s | FileCheck %s
22

3+
// CHECK-LABEL: sil_coverage_map {{.*}}// coverage_closures.bar
4+
func bar(arr: [(Int32) -> Int32]) {
5+
// CHECK: [[@LINE+1]]:13 -> [[@LINE+1]]:42
6+
for a in [{ (b : Int32) -> Int32 in b }] {
7+
a(0)
8+
}
9+
}
10+
311
// CHECK-LABEL: sil_coverage_map {{.*}}// coverage_closures.foo
412
func foo() {
513
// CHECK: [[@LINE+1]]:12 -> [[@LINE+1]]:59 : 1
@@ -19,4 +27,5 @@ func foo() {
1927
f1 { left, right in left == 0 || right == 1 }
2028
}
2129

30+
bar(arr: [{ x in x }])
2231
foo()

0 commit comments

Comments
 (0)