Skip to content

Commit b74cdf1

Browse files
committed
Derive the SILDebugScope for a variable declaration from its owning ASTScope.
The previous code made the assumption that the ASTScope for a variable declaration should be the one of the declaration's source location. That is not necessarily the case, in some cases it should be an ancestor scope. This patch introduces a map from ValueDecl -> ASTScope that is derived from querying each ASTScope for its locals, which matches also what happens in name lookup. This patch also fixes the nesting of SILDebugScopes created for guard statement bodies, which are incorrectly nested in the ASTScope hierarchy. rdar://108940570
1 parent a0ec3f4 commit b74cdf1

13 files changed

+114
-78
lines changed

lib/SILGen/SILGenFunction.cpp

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "swift/AST/PropertyWrappers.h"
3333
#include "swift/AST/SourceFile.h"
3434
#include "swift/AST/Types.h"
35+
#include "swift/Basic/Defer.h"
3536
#include "swift/SIL/SILArgument.h"
3637
#include "swift/SIL/SILProfiler.h"
3738
#include "swift/SIL/SILUndef.h"
@@ -201,7 +202,17 @@ const SILDebugScope *SILGenFunction::getScopeOrNull(SILLocation Loc,
201202
SourceLoc SLoc = Loc.getSourceLoc();
202203
if (!SF || LastSourceLoc == SLoc)
203204
return nullptr;
204-
return getOrCreateScope(SLoc);
205+
// Prime VarDeclScopeMap.
206+
auto Scope = getOrCreateScope(SLoc);
207+
if (ForMetaInstruction)
208+
if (ValueDecl *ValDecl = Loc.getAsASTNode<ValueDecl>()) {
209+
// The source location of a VarDecl isn't necessarily in the same scope
210+
// that the variable resides in for name lookup purposes.
211+
auto ValueScope = VarDeclScopeMap.find(ValDecl);
212+
if (ValueScope != VarDeclScopeMap.end())
213+
return getOrCreateScope(ValueScope->second, F.getDebugScope());
214+
}
215+
return Scope;
205216
}
206217

207218
const SILDebugScope *SILGenFunction::getOrCreateScope(SourceLoc SLoc) {
@@ -378,9 +389,14 @@ SILGenFunction::getOrCreateScope(const ast_scope::ASTScopeImpl *ASTScope,
378389
if (It != ScopeMap.end())
379390
return It->second;
380391

381-
LLVM_DEBUG( ASTScope->print(llvm::errs(), 0, false, false) );
392+
LLVM_DEBUG(ASTScope->print(llvm::errs(), 0, false, false));
382393

383-
SILDebugScope *SILScope = nullptr;
394+
auto cache = [&](const SILDebugScope *SILScope) {
395+
ScopeMap.insert({{ASTScope, InlinedAt}, SILScope});
396+
assert(SILScope->getParentFunction() == &F &&
397+
"inlinedAt points to other function");
398+
return SILScope;
399+
};
384400

385401
// Decide whether to pick a parent scope instead.
386402
if (ASTScope->ignoreInDebugInfo()) {
@@ -390,44 +406,68 @@ SILGenFunction::getOrCreateScope(const ast_scope::ASTScopeImpl *ASTScope,
390406
return ParentScope->InlinedCallSite != InlinedAt ? FnScope : ParentScope;
391407
}
392408

409+
// Collect all variable declarations in this scope.
410+
struct Consumer : public namelookup::AbstractASTScopeDeclConsumer {
411+
const ast_scope::ASTScopeImpl *ASTScope;
412+
VarDeclScopeMapTy &VarDeclScopeMap;
413+
Consumer(const ast_scope::ASTScopeImpl *ASTScope,
414+
VarDeclScopeMapTy &VarDeclScopeMap)
415+
: ASTScope(ASTScope), VarDeclScopeMap(VarDeclScopeMap) {}
416+
417+
bool consume(ArrayRef<ValueDecl *> values,
418+
NullablePtr<DeclContext> baseDC) override {
419+
for (auto &value : values) {
420+
assert(VarDeclScopeMap.count(value) == 0 && "VarDecl appears twice");
421+
VarDeclScopeMap.insert({value, ASTScope});
422+
}
423+
return false;
424+
}
425+
bool lookInMembers(const DeclContext *) const override { return false; }
426+
#ifndef NDEBUG
427+
void startingNextLookupStep() override {}
428+
void finishingLookup(std::string) const override {}
429+
bool isTargetLookup() const override { return false; }
430+
#endif
431+
};
432+
Consumer consumer(ASTScope, VarDeclScopeMap);
433+
ASTScope->lookupLocalsOrMembers(consumer);
434+
393435
// Collapse BraceStmtScopes whose parent is a .*BodyScope.
394436
if (auto Parent = ASTScope->getParent().getPtrOrNull())
395437
if (Parent->getSourceRangeOfThisASTNode() ==
396438
ASTScope->getSourceRangeOfThisASTNode())
397-
return getOrCreateScope(Parent, FnScope, InlinedAt);
439+
return cache(getOrCreateScope(Parent, FnScope, InlinedAt));
398440

399441
// The calls to defer closures have cleanup source locations pointing to the
400442
// defer. Reparent them into the current debug scope.
401443
auto *AncestorScope = ASTScope->getParent().getPtrOrNull();
402444
while (AncestorScope && AncestorScope != FnASTScope &&
403445
!ScopeMap.count({AncestorScope, InlinedAt})) {
404446
if (auto *FD = dyn_cast_or_null<FuncDecl>(
405-
AncestorScope->getDeclIfAny().getPtrOrNull())) {
447+
AncestorScope->getDeclIfAny().getPtrOrNull())) {
406448
if (cast<DeclContext>(FD) != FunctionDC)
407-
return B.getCurrentDebugScope();
449+
return cache(B.getCurrentDebugScope());
408450

409451
// This is this function's own scope.
410452
// If this is the outermost BraceStmt scope, ignore it.
411453
if (AncestorScope == ASTScope->getParent().getPtrOrNull())
412-
return FnScope;
454+
return cache(FnScope);
413455
break;
414456
}
415457

416458
AncestorScope = AncestorScope->getParent().getPtrOrNull();
417459
};
418460

461+
// Create the scope and recursively its parents. getLookupParent implements a
462+
// special case for GuardBlockStmt, which is nested incorrectly.
463+
auto *ParentScope = ASTScope->getLookupParent().getPtrOrNull();
419464
const SILDebugScope *Parent =
420-
getOrCreateScope(ASTScope->getParent().getPtrOrNull(), FnScope, InlinedAt);
465+
getOrCreateScope(ParentScope, FnScope, InlinedAt);
421466
SourceLoc SLoc = ASTScope->getSourceRangeOfThisASTNode().Start;
422467
RegularLocation Loc(SLoc);
423-
SILScope = new (SGM.M)
468+
auto *SILScope = new (SGM.M)
424469
SILDebugScope(Loc, FnScope->getParentFunction(), Parent, InlinedAt);
425-
ScopeMap.insert({{ASTScope, InlinedAt}, SILScope});
426-
427-
assert(SILScope->getParentFunction() == &F &&
428-
"inlinedAt points to other function");
429-
430-
return SILScope;
470+
return cache(SILScope);
431471
}
432472

433473
void SILGenFunction::enterDebugScope(SILLocation Loc, bool isBindingScope) {

lib/SILGen/SILGenFunction.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
366366
SourceLoc LastSourceLoc;
367367
using ASTScopeTy = ast_scope::ASTScopeImpl;
368368
const ASTScopeTy *FnASTScope = nullptr;
369+
using VarDeclScopeMapTy =
370+
llvm::SmallDenseMap<ValueDecl *, const ASTScopeTy *, 8>;
371+
/// The ASTScope each variable declaration belongs to.
372+
VarDeclScopeMapTy VarDeclScopeMap;
369373
/// Caches one SILDebugScope for each ASTScope.
370374
llvm::SmallDenseMap<std::pair<const ASTScopeTy *, const SILDebugScope *>,
371375
const SILDebugScope *, 16>

test/DebugInfo/for-scope.swift

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ public func f(_ xs: [String?]) {
88
sink(x)
99
}
1010
}
11+
1112
// CHECK: sil_scope [[F:[0-9]+]] { loc "{{.*}}":5:13 parent @$s1a1fyySaySSSgGF
12-
// CHECK: sil_scope [[S0:[0-9]+]] { loc "{{.*}}":6:3 parent [[F]] }
13-
// CHECK: sil_scope [[S1:[0-9]+]] { loc "{{.*}}":6:15 parent [[S0]] }
14-
// CHECK: sil_scope [[S3:[0-9]+]] { loc "{{.*}}":7:9 parent [[S1]] }
15-
// CHECK: sil_scope [[S4:[0-9]+]] { loc "{{.*}}":7:13 parent [[S3]] }
13+
// CHECK: sil_scope [[S3:[0-9]+]] { loc "{{.*}}":6:3 parent [[F]] }
14+
// CHECK: sil_scope [[S4:[0-9]+]] { loc "{{.*}}":6:15 parent [[S3]] }
15+
// CHECK: sil_scope [[S5:[0-9]+]] { loc "{{.*}}":7:13 parent [[S4]] }
16+
// CHECK: sil_scope [[S6:[0-9]+]] { loc "{{.*}}":7:9 parent [[S4]] }
1617

17-
// CHECK: debug_value %[[X:.*]] : $Optional<String>, let, name "x", {{.*}}, scope [[S0]]
18-
// CHECK: retain_value %[[X]] : $Optional<String>, {{.*}}, scope [[S4]]
19-
// CHECK: debug_value %[[X1:[0-9]+]] : $String, let, name "x", {{.*}}, scope [[S3]]
20-
// CHECK: release_value %[[X1]] : $String, {{.*}}, scope [[S3]]
21-
// CHECK: release_value %[[X]] : $Optional<String>, {{.*}}, scope [[S3]]
18+
// CHECK: debug_value %[[X:.*]] : $Optional<String>, let, name "x", {{.*}}, scope [[S3]]
19+
// CHECK: retain_value %[[X]] : $Optional<String>, {{.*}}, scope [[S5]]
20+
// CHECK: debug_value %[[X1:[0-9]+]] : $String, let, name "x", {{.*}}, scope [[S6]]
21+
// CHECK: release_value %[[X1]] : $String, {{.*}}, scope [[S6]]
22+
// CHECK: release_value %[[X]] : $Optional<String>, {{.*}}, scope [[S6]]

test/DebugInfo/guard-let-scope.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ func f(c: AnyObject??) {
77
guard let x = x, let x = x else {
88
// CHECK: sil_scope [[S3:[0-9]+]] { {{.*}} parent @{{.*}}1f
99
// CHECK: sil_scope [[S4:[0-9]+]] { {{.*}} parent [[S3]] }
10-
// CHECK: sil_scope [[S5:[0-9]+]] { {{.*}} parent [[S4]] }
11-
// CHECK: sil_scope [[S6:[0-9]+]] { loc "{{.*}}":7:3 parent [[S4]] }
10+
// CHECK: sil_scope [[S5:[0-9]+]] { {{.*}} parent [[S3]] }
11+
// CHECK: sil_scope [[S6:[0-9]+]] { loc "{{.*}}":7:3 parent [[S5]] }
1212
// CHECK: sil_scope [[S7:[0-9]+]] { loc "{{.*}}":7:17 parent [[S6]] }
1313
// CHECK: sil_scope [[S8:[0-9]+]] { loc "{{.*}}":7:28 parent [[S7]] }
14-
// CHECK: debug_value %{{.*}} : $Optional<Optional<AnyObject>>, let, name "x"{{.*}} scope [[S4]]
15-
// CHECK: debug_value %{{.*}} : $Optional<AnyObject>, let, name "x", {{.*}} scope [[S6]]
16-
// CHECK: debug_value %{{.*}} : $AnyObject, let, name "x", {{.*}} scope [[S7]]
14+
// CHECK: debug_value %{{.*}} : $Optional<Optional<AnyObject>>, let, name "x"{{.*}} scope [[S5]]
15+
// CHECK: debug_value %{{.*}} : $Optional<AnyObject>, let, name "x", {{.*}} scope [[S7]]
16+
// CHECK: debug_value %{{.*}} : $AnyObject, let, name "x", {{.*}} scope [[S8]]
1717
fatalError()
1818
}
1919
// CHECK: function_ref {{.*3use.*}} scope [[S8]]

test/DebugInfo/guard-let-scope2.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public func f(x: String?) throws {
1818
}
1919
// CHECK: sil_scope [[S1:[0-9]+]] { {{.*}} parent @{{.*}}1f
2020
// CHECK: sil_scope [[S2:[0-9]+]] { {{.*}} parent [[S1]] }
21-
// CHECK: sil_scope [[S3:[0-9]+]] { {{.*}} parent [[S2]] }
21+
// CHECK: sil_scope [[S3:[0-9]+]] { {{.*}} parent [[S1]] }
2222
// CHECK: sil_scope [[S4:[0-9]+]] { {{.*}} parent [[S2]] }
2323
// CHECK: alloc_stack {{.*}} $SomeObject, let, name "s", {{.*}} scope [[S4]]
2424
guard let s = s else {

test/DebugInfo/guard-let-scope3.swift

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@ public class S {
77
private var c = [Int : C?]()
88
public func f(_ i: Int) throws -> C {
99
guard let x = c[i], let x else {
10-
// CHECK: sil_scope [[X1:[0-9]+]] { loc "{{.*}}":[[@LINE-1]]:5
11-
// CHECK: sil_scope [[X2:[0-9]+]] { loc "{{.*}}":[[@LINE-2]]:29
12-
// CHECK: debug_value {{.*}} : $Optional<C>, let, name "x", {{.*}}, scope [[X1]]
13-
// CHECK: debug_value %29 : $C, let, name "x", {{.*}}, scope [[X2]]
14-
// CHECK-NEXT: scope [[X2]]
10+
// CHECK: sil_scope [[P:[0-9]+]] { loc "{{.*}}":[[@LINE-1]]:5
11+
// CHECK: sil_scope [[X1:[0-9]+]] { loc "{{.*}}":[[@LINE-2]]:19 parent [[P]]
12+
// CHECK: sil_scope [[X2:[0-9]+]] { loc "{{.*}}":[[@LINE-3]]:29 parent [[X1]]
13+
// CHECK: sil_scope [[GUARD:[0-9]+]] { loc "{{.*}}":[[@LINE-4]]:36 parent [[P]]
14+
// CHECK: debug_value {{.*}} : $Optional<C>, let, name "x", {{.*}}, scope [[X1]]
15+
// CHECK: debug_value {{.*}} : $C, let, name "x", {{.*}}, scope [[X2]]
16+
// CHECK-NEXT: scope [[X2]]
1517
throw MyError()
18+
// CHECK: function_ref {{.*}}MyError{{.*}}:[[@LINE-1]]:13, scope [[GUARD]]
1619
}
1720
return x
1821
}

test/DebugInfo/if-let-scope.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %target-swift-frontend -g -emit-sil %s -parse-as-library -module-name a | %FileCheck %s
2+
func use<T>(_ t: T) {}
3+
public func f(value: String?) {
4+
// CHECK: sil_scope [[S0:[0-9]+]] { loc "{{.*}}":[[@LINE-1]]:13
5+
if let value, let value = Int(value) {
6+
// CHECK: sil_scope [[S1:[0-9]+]] { loc "{{.*}}":[[@LINE-1]]:10
7+
// CHECK: sil_scope [[S2:[0-9]+]] { loc "{{.*}}":[[@LINE-2]]:29 parent [[S1]] }
8+
// CHECK: debug_value {{.*}} : $Optional<String>, let, name "value", {{.*}}, scope [[S0]]
9+
// CHECK: debug_value {{.*}} : $String, let, name "value", {{.*}}, scope [[S1]]
10+
// CHECK: debug_value {{.*}} : $Int, let, name "value", {{.*}}, scope [[S2]]
11+
use((value))
12+
}
13+
}

test/DebugInfo/inlinescopes.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,9 @@ func inlined(_ x: Int64) -> Int64 {
2727
let result = transparent(x)
2828
// CHECK-DAG: ![[CALL]] = !DILocation(line: [[@LINE-1]], column: {{.*}}, scope: ![[INLINED1:.*]], inlinedAt: ![[INLINEDAT:.*]])
2929
// CHECK-DAG: ![[INLINEDAT]] = !DILocation({{.*}}scope: ![[INLINEDAT1:[0-9]+]]
30-
// CHECK-DAG: ![[INLINED1]] = distinct !DILexicalBlock(scope: ![[INLINED2:[0-9]+]]
31-
// CHECK-DAG: ![[INLINED2]] = distinct !DILexicalBlock(scope: ![[INLINED3:[0-9]+]]
30+
// CHECK-DAG: ![[INLINED1]] = distinct !DILexicalBlock(scope: ![[INLINED:[0-9]+]]
3231
// Check if the inlined and removed function still has the correct linkage name.
33-
// CHECK-DAG: ![[INLINED3]] = distinct !DISubprogram(name: "inlined", linkageName: "$s4main7inlinedys5Int64VADF"
32+
// CHECK-DAG: ![[INLINED]] = distinct !DISubprogram(name: "inlined", linkageName: "$s4main7inlinedys5Int64VADF"
3433
// TRANSPARENT-CHECK-NOT: !DISubprogram(name: "transparent"
3534
return result
3635
}

test/DebugInfo/let-scope.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: %target-swift-frontend -g -emit-sil %s -parse-as-library -module-name a | %FileCheck %s
2+
func use<T>(_ t: T) {}
3+
public func f(value: (Int, Int)) {
4+
let (x, y) = value
5+
// CHECK: debug_value {{.*}}let, name "x", {{.*}}, scope [[LET:[0-9]+]]
6+
// CHECK: debug_value {{.*}}let, name "y", {{.*}}, scope [[LET]]
7+
use((x,y))
8+
}

test/DebugInfo/scopes.swift

Lines changed: 0 additions & 32 deletions
This file was deleted.

test/DebugInfo/shadowed-arg.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@ public func f(i: Int) {
1717
// CHECK: ![[S3]] = distinct !DILexicalBlock(scope: ![[S1]],
1818
// SIL: sil_scope [[S1:[0-9]+]] { {{.*}} parent @$s4main1f1iySi_tF
1919
// SIL: sil_scope [[S2:[0-9]+]] { {{.*}} parent [[S1]] }
20+
// SIL: sil_scope [[S3:[0-9]+]] { {{.*}} parent [[S1]] }
2021
// SIL: debug_value %0 : $Int, let, name "i", argno 1,{{.*}}, scope [[S1]]
21-
// SIL: debug_value {{.*}} : $Array<Int>, let, name "i", {{.*}}, scope [[S2]]
22+
// SIL: debug_value {{.*}} : $Array<Int>, let, name "i", {{.*}}, scope [[S3]]

test/Macros/macro_expand_closure.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ func multiStatementInference() -> Int {
2020
// The closure intruduced by the macro expansion should not contain any inline
2121
// locations, but instead point directly into the macro buffer.
2222
// CHECK-SIL: sil_scope [[S0:[0-9]+]] { loc "@__swiftmacro_9MacroUser23multiStatementInferenceSiyF0cD0fMf_.swift":1:1 parent @$s9MacroUser23multiStatementInferenceSiyFSiyXEfU_
23-
// CHECK-SIL: sil_scope [[S1:[0-9]+]] { loc "@__swiftmacro_9MacroUser23multiStatementInferenceSiyF0cD0fMf_.swift":2:7 parent [[S0]] }
24-
// CHECK-SIL: sil_scope [[S2:[0-9]+]] { loc "@__swiftmacro_9MacroUser23multiStatementInferenceSiyF0cD0fMf_.swift":2:14 parent [[S1]] }
23+
// CHECK-SIL: sil_scope [[S2:[0-9]+]] { loc "@__swiftmacro_9MacroUser23multiStatementInferenceSiyF0cD0fMf_.swift":2:14 parent [[S0]] }
2524

2625
// CHECK-SIL: sil {{.*}} @$s9MacroUser23multiStatementInferenceSiyFSiyXEfU_
2726
// CHECK-SIL-NOT: return

test/SILOptimizer/capturepromotion-wrong-lexicalscope.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919
// CHECK: destroy_value [[BOX_COPY]] : ${ var Int }, loc {{.*}}:33:11, scope 4
2020
// CHECK: [[CLOSURE:%[^,]+]] = partial_apply [callee_guaranteed] [[SPECIALIZED_F]]([[REGISTER_11]]) : $@convention(thin) (Int) -> Int, loc {{.*}}:33:11, scope 4
2121
// CHECK: [[BORROW:%.*]] = begin_borrow [lexical] [[CLOSURE]]
22-
// CHECK: debug_value [[BORROW]] : $@callee_guaranteed () -> Int, let, name "f", loc {{.*}}:33:7, scope 5
23-
// CHECK: [[CLOSURE_COPY:%[^,]+]] = copy_value [[BORROW]] : $@callee_guaranteed () -> Int, loc {{.*}}:34:10, scope 5
22+
// CHECK: debug_value [[BORROW]] : $@callee_guaranteed () -> Int, let, name "f", loc {{.*}}:33:7, scope 6
23+
// CHECK: [[CLOSURE_COPY:%[^,]+]] = copy_value [[BORROW]] : $@callee_guaranteed () -> Int, loc {{.*}}:34:10, scope 6
2424
// There used to be an end_borrow here. We leave an emptyline here to preserve line numbers.
25-
// CHECK: destroy_value [[CLOSURE]] : $@callee_guaranteed () -> Int, loc {{.*}}:35:1, scope 5
26-
// CHECK: destroy_value [[BOX]] : ${ var Int }, loc {{.*}}:35:1, scope 5
27-
// CHECK: return [[CLOSURE_COPY]] : $@callee_guaranteed () -> Int, loc {{.*}}:34:3, scope 5
25+
// CHECK: destroy_value [[CLOSURE]] : $@callee_guaranteed () -> Int, loc {{.*}}:35:1, scope 6
26+
// CHECK: destroy_value [[BOX]] : ${ var Int }, loc {{.*}}:35:1, scope 6
27+
// CHECK: return [[CLOSURE_COPY]] : $@callee_guaranteed () -> Int, loc {{.*}}:34:3, scope 6
2828
// CHECK: }
2929

3030

0 commit comments

Comments
 (0)