Skip to content

Commit 0aea1c0

Browse files
committed
Debug Info: Represent private discriminators in DWARF.
... using an inline namespace as the parent of the outermost declaration(s) that have private or fileprivate accessability. Once LLDB supports this we can retire the existing hack of storing it as a fake command line argument. rdar://problem/18296829
1 parent b164fdb commit 0aea1c0

File tree

5 files changed

+100
-39
lines changed

5 files changed

+100
-39
lines changed

include/swift/AST/Decl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2207,6 +2207,9 @@ class ValueDecl : public Decl {
22072207
return result;
22082208
}
22092209

2210+
/// Determine whether this Decl has either Private or FilePrivate access.
2211+
bool isOutermostPrivateOrFilePrivateScope() const;
2212+
22102213
/// Returns the outermost DeclContext from which this declaration can be
22112214
/// accessed, or null if the declaration is public.
22122215
///

lib/AST/ASTMangler.cpp

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -533,25 +533,6 @@ void ASTMangler::appendSymbolKind(SymbolKind SKind) {
533533
}
534534
}
535535

536-
/// Returns true if one of the ancestor DeclContexts of \p D is either marked
537-
/// private or is a local context.
538-
static bool isInPrivateOrLocalContext(const ValueDecl *D) {
539-
const DeclContext *DC = D->getDeclContext();
540-
if (!DC->isTypeContext()) {
541-
assert((DC->isModuleScopeContext() || DC->isLocalContext()) &&
542-
"unexpected context kind");
543-
return DC->isLocalContext();
544-
}
545-
546-
auto *nominal = DC->getAsNominalTypeOrNominalTypeExtensionContext();
547-
if (nominal == nullptr)
548-
return false;
549-
550-
if (nominal->getFormalAccess() <= AccessLevel::FilePrivate)
551-
return true;
552-
return isInPrivateOrLocalContext(nominal);
553-
}
554-
555536
static bool getUnnamedParamIndex(const ParameterList *ParamList,
556537
const ParamDecl *D,
557538
unsigned &UnnamedIndex) {
@@ -593,11 +574,8 @@ static unsigned getUnnamedParamIndex(const ParamDecl *D) {
593574
}
594575

595576
static StringRef getPrivateDiscriminatorIfNecessary(const ValueDecl *decl) {
596-
if (!decl->hasAccess() ||
597-
decl->getFormalAccess() > AccessLevel::FilePrivate ||
598-
isInPrivateOrLocalContext(decl)) {
577+
if (!decl->isOutermostPrivateOrFilePrivateScope())
599578
return StringRef();
600-
}
601579

602580
// Mangle non-local private declarations with a textual discriminator
603581
// based on their enclosing file.

lib/AST/Decl.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,6 +1433,34 @@ AbstractStorageDecl::getAccessStrategy(AccessSemantics semantics,
14331433
llvm_unreachable("bad access semantics");
14341434
}
14351435

1436+
static bool hasPrivateOrFilePrivateFormalAccess(const ValueDecl *D) {
1437+
return D->hasAccess() && D->getFormalAccess() <= AccessLevel::FilePrivate;
1438+
}
1439+
1440+
/// Returns true if one of the ancestor DeclContexts of this ValueDecl is either
1441+
/// marked private or fileprivate or is a local context.
1442+
static bool isInPrivateOrLocalContext(const ValueDecl *D) {
1443+
const DeclContext *DC = D->getDeclContext();
1444+
if (!DC->isTypeContext()) {
1445+
assert((DC->isModuleScopeContext() || DC->isLocalContext()) &&
1446+
"unexpected context kind");
1447+
return DC->isLocalContext();
1448+
}
1449+
1450+
auto *nominal = DC->getAsNominalTypeOrNominalTypeExtensionContext();
1451+
if (nominal == nullptr)
1452+
return false;
1453+
1454+
if (hasPrivateOrFilePrivateFormalAccess(nominal))
1455+
return true;
1456+
return isInPrivateOrLocalContext(nominal);
1457+
}
1458+
1459+
bool ValueDecl::isOutermostPrivateOrFilePrivateScope() const {
1460+
return hasPrivateOrFilePrivateFormalAccess(this) &&
1461+
!isInPrivateOrLocalContext(this);
1462+
}
1463+
14361464
bool AbstractStorageDecl::hasFixedLayout() const {
14371465
// If we're in a nominal type, just query the type.
14381466
auto *dc = getDeclContext();

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,6 +1395,19 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
13951395
return nullptr;
13961396
}
13971397

1398+
/// The private discriminator is represented as an inline namespace.
1399+
llvm::DIScope *getFilePrivateScope(llvm::DIScope *Parent, TypeDecl *Decl,
1400+
DeclContext *Context) {
1401+
// Retrieve the private discriminator.
1402+
if (auto *SF = Context->getParentSourceFile()) {
1403+
auto PrivateDiscriminator = SF->getPrivateDiscriminator();
1404+
if (!PrivateDiscriminator.empty())
1405+
return DBuilder.createNameSpace(Parent, PrivateDiscriminator.str(),
1406+
/*ExportSymbols=*/true);
1407+
}
1408+
llvm_unreachable("unknown private discriminator");
1409+
}
1410+
13981411
llvm::DIType *getOrCreateType(DebugTypeInfo DbgTy) {
13991412
// Is this an empty type?
14001413
if (DbgTy.isNull())
@@ -1438,6 +1451,13 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
14381451
}
14391452
if (!Scope)
14401453
Scope = getOrCreateContext(Context);
1454+
1455+
// Scope outermost fileprivate decls in an inline private discriminator
1456+
// namespace.
1457+
if (auto *Decl = DbgTy.getDecl())
1458+
if (Context && Decl->isOutermostPrivateOrFilePrivateScope())
1459+
Scope = getFilePrivateScope(Scope, Decl, Context);
1460+
14411461
llvm::DIType *DITy = createType(DbgTy, MangledName, Scope, getFile(Scope));
14421462

14431463
// Incrementally build the DIRefMap.
@@ -1518,9 +1538,9 @@ IRGenDebugInfoImpl::IRGenDebugInfoImpl(const IRGenOptions &Opts,
15181538
CU_Nodes->addOperand(*CU);
15191539

15201540
// Create a module for the current compile unit.
1541+
auto *MDecl = IGM.getSwiftModule();
15211542
llvm::sys::path::remove_filename(AbsMainFile);
1522-
MainModule = getOrCreateModule(IGM.getSwiftModule(), TheCU, Opts.ModuleName,
1523-
AbsMainFile);
1543+
MainModule = getOrCreateModule(MDecl, TheCU, Opts.ModuleName, AbsMainFile);
15241544
DBuilder.createImportedModule(MainFile, MainModule, MainFile, 0);
15251545

15261546
// Macro definitions that were defined by the user with "-Xcc -D" on the
Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,57 @@
11
// Private discriminators should only be emitted for multi-file projects.
22

3-
// RUN: %target-swift-frontend -emit-ir %s -g -o - | %FileCheck --check-prefix=SINGLE %s
3+
// RUN: %target-swift-frontend -emit-ir %s -g -o - \
4+
// RUN: | %FileCheck --check-prefix=SINGLE %s
45
// SINGLE-NOT: !DICompileUnit({{.*}}-private-discriminator
56

6-
// RUN: %target-swift-frontend %S/../Inputs/empty.swift -primary-file %s -emit-ir -g | %FileCheck %s
7+
// RUN: %target-swift-frontend %S/../Inputs/empty.swift -primary-file %s \
8+
// RUN: -emit-ir -g | %FileCheck %s
79
// CHECK: !DICompileUnit({{.*}}flags: {{[^,]*}}-private-discriminator [[DISCRIMINATOR:_[A-Z0-9]+]]
10+
// CHECK: ![[MOD:.*]] = !DIModule(scope: null,
11+
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "InA",
12+
// CHECK-SAME: scope: ![[A:[0-9]+]],
13+
// CHECK: ![[A]] = !DICompositeType(tag: DW_TAG_structure_type, name: "A",
14+
// CHECK-SAME: scope: ![[NS:[0-9]+]]
15+
// CHECK: !DINamespace(name: "[[DISCRIMINATOR]]",
16+
// CHECK-SAME: scope: ![[OUTER:[0-9]+]], exportSymbols: true)
17+
// CHECK: ![[OUTER]] = !DICompositeType(tag: DW_TAG_structure_type,
18+
// CHECK-SAME: name: "Outer",
19+
// CHECK-SAME: scope: ![[MOD]],
820

921
func markUsed<T>(_ t: T) {}
1022

11-
private class A {
12-
init(val : Int64) { member = val }
13-
private let member : Int64
14-
// CHECK: !DISubprogram(name: "getMember"
15-
// CHECK-SAME: linkageName: "{{[^"]*}}[[DISCRIMINATOR]]
16-
// CHECK-SAME: line: [[@LINE+2]]
17-
// CHECK-SAME: isLocal: true, isDefinition: true
18-
private func getMember() -> Int64 { return member }
19-
func getVal() -> Int64 { return getMember() }
23+
public class Outer {
24+
fileprivate class A {
25+
fileprivate struct InA {
26+
let i : Int64
27+
init(_ val : Int64) { i = val }
28+
}
29+
30+
init(val : Int64) { member = InA(val) }
31+
fileprivate let member : InA
32+
// CHECK: !DISubprogram(name: "getMember"
33+
// CHECK-SAME: linkageName: "{{[^"]*}}[[DISCRIMINATOR]]
34+
// CHECK-SAME: line: [[@LINE+2]]
35+
// CHECK-SAME: isLocal: true, isDefinition: true
36+
fileprivate func getMember() -> Int64 { return member.i }
37+
}
2038
}
2139

22-
func f() {
23-
let a = A(val: 42)
24-
markUsed(a.getVal())
40+
// CHECK: ![[G:[0-9]+]] = distinct !DISubprogram(name: "g",
41+
// CHECK-SAME: scope: ![[MOD]]
42+
fileprivate func g() -> Int64 {
43+
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "InG",
44+
// CHECK-SAME: scope: ![[G]],
45+
struct InG {
46+
let i : Int64
47+
init(_ val : Int64) { i = val }
48+
}
49+
50+
return InG(42).i
51+
}
52+
53+
// CHECK: distinct !DISubprogram(name: "f", {{.*}}, scope: ![[MOD]]
54+
public func f() {
55+
let a = Outer.A(val: g())
56+
markUsed(a)
2557
}

0 commit comments

Comments
 (0)