Skip to content

Commit e881168

Browse files
committed
Debug Info: Avoid type uniquing clashes for bound generic enums.
This patch changes the DWARF representation of bound generic enums to a nested struct where the (sized) outer struct is anonymous and thus distinct and the inner struct in uniqued and sizeless. BoundGenericEnums may have different sizes depending on what they are bound to, but still share a mangled name. rdar://problem/56521648
1 parent ed82942 commit e881168

File tree

6 files changed

+132
-13
lines changed

6 files changed

+132
-13
lines changed

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,29 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
10001000
return BitWidth;
10011001
}
10021002

1003+
/// Create a sized container for a sizeless type. Used to represent
1004+
/// BoundGenericEnums that may have different sizes depending on what they are
1005+
/// bound to, but still share a mangled name.
1006+
llvm::DIType *createOpaqueStructWithSizedContainer(
1007+
llvm::DIScope *Scope, StringRef Name, llvm::DIFile *File, unsigned Line,
1008+
unsigned SizeInBits, unsigned AlignInBits, llvm::DINode::DIFlags Flags,
1009+
StringRef MangledName) {
1010+
// Let the MDNode folding set do the work of uniquing the inner type. This
1011+
// should be cheap.
1012+
llvm::DICompositeType *UniqueType = DBuilder.createStructType(
1013+
Scope, Name, File, Line, 0, 0, Flags, nullptr,
1014+
DBuilder.getOrCreateArray(ArrayRef<llvm::Metadata *>()),
1015+
llvm::dwarf::DW_LANG_Swift, nullptr, MangledName);
1016+
llvm::Metadata *Elements[] = {
1017+
DBuilder.createMemberType(Scope, "", File, 0, SizeInBits,
1018+
AlignInBits, 0, Flags, UniqueType)};
1019+
1020+
return DBuilder.createStructType(
1021+
Scope, "", File, Line, SizeInBits, AlignInBits, Flags,
1022+
/* DerivedFrom */ nullptr, DBuilder.getOrCreateArray(Elements),
1023+
llvm::dwarf::DW_LANG_Swift);
1024+
}
1025+
10031026
llvm::DIType *createPointerSizedStruct(llvm::DIScope *Scope, StringRef Name,
10041027
llvm::DIFile *File, unsigned Line,
10051028
llvm::DINode::DIFlags Flags,
@@ -1413,12 +1436,9 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
14131436
auto *Decl = EnumTy->getDecl();
14141437
auto L = getDebugLoc(*this, Decl);
14151438
auto *File = getOrCreateFile(L.Filename);
1416-
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes)
1417-
return createEnumType(DbgTy, Decl, MangledName, Scope, File, L.Line,
1418-
Flags);
1419-
else
1420-
return createOpaqueStruct(Scope, Decl->getName().str(), File, L.Line,
1421-
SizeInBits, AlignInBits, Flags, MangledName);
1439+
return createOpaqueStructWithSizedContainer(
1440+
Scope, Decl->getName().str(), File, L.Line, SizeInBits, AlignInBits,
1441+
Flags, MangledName);
14221442
}
14231443

14241444
case TypeKind::BuiltinVector: {

test/DebugInfo/BoundGenericEnum.swift

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// RUN: %target-swift-frontend %s -Onone -emit-ir -g -o - -module-name a \
2+
// RUN: -disable-debugger-shadow-copies | %FileCheck %s
3+
public enum Result<Value> {
4+
case success(Value)
5+
case failure(Error)
6+
}
7+
8+
extension Result {
9+
public func map<U>(_ transform: (Value) -> U) -> Result<U> {
10+
switch self {
11+
case .success(let value):
12+
return .success(transform(value))
13+
case .failure(let error):
14+
return .failure(error)
15+
}
16+
}
17+
}
18+
19+
func use<T>(_ t : T) {
20+
}
21+
22+
public class SomeClass {
23+
public let s = "hello"
24+
}
25+
26+
extension Result where Value : SomeClass {
27+
public func f() -> Self {
28+
use(self)
29+
return map({ $0 })
30+
}
31+
}
32+
33+
extension Result {
34+
public func g() {
35+
use(self)
36+
}
37+
}
38+
39+
let x : Result<SomeClass> = .success(SomeClass())
40+
let y : Result<(Int64, Int64, Int64, Int64)> = .success((1, 2, 3, 4))
41+
x.f()
42+
y.g()
43+
44+
// Here we have three types, all named $s1a6ResultOyxGD (---> a.Result<A>),
45+
// but with different storage sizes:
46+
//
47+
// 0. Unsized from the subroutine tupe of map<U>.
48+
// 1. Enum wrapping a pointer-sized object [map() and f()].
49+
// 2. Enum wrapping a 4x64-bit tuple.
50+
//
51+
// Test that bound generic enums are *not* using their mangled name as a unique
52+
// identifier.
53+
54+
// (0) unsized.
55+
// CHECK: !DISubprogram(name: "map", {{.*}}line: 9, type: ![[SBTY:[0-9]+]]
56+
// CHECK: ![[SBTY]] = !DISubroutineType(types: ![[SBTYS:[0-9]+]])
57+
// CHECK: ![[SBTYS]] = !{!{{[0-9]+}}, !{{[0-9]+}}, ![[SELFTY:[0-9]+]]}
58+
// CHECK: ![[SELFTY]] =
59+
// CHECK-SAME: !DICompositeType(tag: DW_TAG_structure_type, {{.*}}line: 3,
60+
// CHECK-SAME: elements: ![[UNSIZED_ELTS:[0-9]+]]
61+
// CHECK: ![[UNSIZED_ELTS]] = !{![[UNSIZED_MEM:[0-9]+]]}
62+
// CHECK: ![[UNSIZED_MEM]] = !DIDerivedType(tag: DW_TAG_member,
63+
// CHECK-SAME: baseType: ![[UNIQ:[0-9]+]]
64+
65+
// The unique unsized type.
66+
// CHECK: ![[UNIQ]] = !DICompositeType(
67+
// CHECK-SAME: tag: DW_TAG_structure_type, name: "Result",
68+
// CHECK-SAME: line: 3,
69+
// CHECK-NOT: size:
70+
// CHECK-SAME: runtimeLang: DW_LANG_Swift,
71+
// CHECK-SAME: identifier: "$s1a6ResultOyxGD")
72+
73+
// (2)
74+
// CHECK: !DILocalVariable(name: "self", arg: 2, {{.*}}line: 9,
75+
// CHECK-SAME: type: ![[C_TUP:[0-9]+]]
76+
// CHECK: ![[C_TUP]] = !DIDerivedType(tag: DW_TAG_const_type,
77+
// CHECK-SAME: baseType: ![[TUP:[0-9]+]])
78+
// CHECK: ![[TUP]] = !DICompositeType(tag: DW_TAG_structure_type,
79+
// CHECK-SAME: line: 3, size: {{256|512}},
80+
81+
// (1)
82+
// CHECK: !DILocalVariable(name: "self", arg: 1, {{.*}}line: 27,
83+
// CHECK-SAME: type: ![[C_CLASS:[0-9]+]]
84+
// CHECK: ![[C_CLASS]] = !DIDerivedType(tag: DW_TAG_const_type,
85+
// CHECK-SAME: baseType: ![[CLASS:[0-9]+]])
86+
// CHECK: ![[CLASS]] = !DICompositeType(tag: DW_TAG_structure_type,
87+
// CHECK-SAME: line: 3, size:

test/DebugInfo/bound-namealiastype.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ func dispatch_queue_create() -> dispatch_queue_t! {
99
}
1010

1111
// CHECK: !DIGlobalVariable(name: "queue",
12-
// CHECK-SAME: line: [[@LINE+3]], type: ![[T:[0-9]+]]
13-
// CHECK: ![[T]] = !DICompositeType(
12+
// CHECK-SAME: line: [[@LINE+6]], type: ![[TY_CONTAINER:[0-9]+]]
13+
// CHECK: ![[TY_CONTAINER]] = !DICompositeType({{.*}}elements: ![[TY_ELTS:[0-9]+]]
14+
// CHECK: ![[TY_ELTS]] = !{![[TY_MEMBER:[0-9]+]]}
15+
// CHECK: ![[TY_MEMBER]] = !DIDerivedType(tag: DW_TAG_member, {{.*}}baseType: ![[TY:[0-9]+]]
16+
// CHECK: ![[TY]] = !DICompositeType(
1417
// CHECK-SAME: identifier: "$s4main16dispatch_queue_taSgD"
1518
public var queue = dispatch_queue_create()

test/DebugInfo/enum.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ let r = Color.Red
5252
let c = MaybeIntPair.just(74, 75)
5353
// CHECK: !DICompositeType({{.*}}name: "Maybe",
5454
// CHECK-SAME: line: [[@LINE-8]],
55-
// CHECK-SAME: size: 8{{[,)]}}
5655
// CHECK-SAME: identifier: "$s4enum5MaybeOyAA5ColorOGD"
5756
let movie : Maybe<Color> = .none
5857

@@ -79,8 +78,12 @@ public enum Tuple<P> {
7978

8079
func bar<T>(_ x : Tuple<T>) -> Tuple<T> { return x }
8180

82-
// CHECK: ![[LIST:.*]] = !DICompositeType({{.*}}identifier: "$s4enum4ListOyxGD"
83-
// CHECK-DAG: ![[LET_LIST:.*]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[LIST]])
81+
// CHECK-DAG: ![[LIST:.*]] = !DICompositeType({{.*}}identifier: "$s4enum4ListOyxGD"
82+
// CHECK-DAG: ![[LIST_MEMBER:.*]] = !DIDerivedType(tag: DW_TAG_member, {{.*}} baseType: ![[LIST]]
83+
// CHECK-DAG: ![[LIST_ELTS:.*]] = !{![[LIST_MEMBER]]}
84+
// CHECK-DAG: ![[LIST_CONTAINER:.*]] = !DICompositeType({{.*}}elements: ![[LIST_ELTS]]
85+
86+
// CHECK-DAG: ![[LET_LIST:.*]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[LIST_CONTAINER]])
8487
// CHECK-DAG: !DILocalVariable(name: "self", arg: 1, {{.*}} line: [[@LINE+4]], type: ![[LET_LIST]], flags: DIFlagArtificial)
8588
public enum List<T> {
8689
indirect case Tail(List, T)

test/DebugInfo/generic_enum.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ func wrapTrivialGeneric<T, U>(_ t: T, u: U) -> TrivialGeneric<T, U> {
1717
return .x(t, u)
1818
}
1919
// CHECK-DAG: ![[T1:.*]] = !DICompositeType({{.*}}identifier: "$s12generic_enum14TrivialGenericOys5Int64VSSGD"
20-
// CHECK-DAG: !DIGlobalVariable(name: "tg",{{.*}} line: [[@LINE+2]],{{.*}} type: ![[T1]],{{.*}} isLocal: false, isDefinition: true
20+
// CHECK-DAG: ![[T1_MEMBER:.*]] = !DIDerivedType(tag: DW_TAG_member, {{.*}}baseType: ![[T1]]
21+
// CHECK-DAG: ![[T1_ELTS:.*]] = !{![[T1_MEMBER]]}
22+
// CHECK-DAG: ![[T1_CONTAINER:.*]] = !DICompositeType({{.*}}elements: ![[T1_ELTS]]
23+
// CHECK-DAG: !DIGlobalVariable(name: "tg",{{.*}} line: [[@LINE+2]],{{.*}} type: ![[T1_CONTAINER]],{{.*}} isLocal: false, isDefinition: true
2124
// CHECK-DAG: !DICompositeType({{.*}}, name: "TrivialGeneric", {{.*}}identifier: "$s12generic_enum14TrivialGenericOys5Int64VSSGD"
2225
var tg : TrivialGeneric<Int64, String> = .x(23, "skidoo")
2326
switch tg {

test/DebugInfo/protocol-sugar.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,8 @@ protocol B {}
44
typealias C = B & A
55
protocol D {}
66
var p: (C & D)?
7-
// CHECK-DAG: !DIGlobalVariable(name: "p", {{.*}}type: ![[TY:[0-9]+]]
7+
// CHECK-DAG: !DIGlobalVariable(name: "p", {{.*}}type: ![[TY_CONTAINER:[0-9]+]]
8+
// CHECK-DAG: ![[TY_CONTAINER]] = !DICompositeType({{.*}}elements: ![[TY_ELTS:[0-9]+]]
9+
// CHECK-DAG: ![[TY_ELTS]] = !{![[TY_MEMBER:[0-9]+]]}
10+
// CHECK-DAG: ![[TY_MEMBER]] = !DIDerivedType(tag: DW_TAG_member, {{.*}}baseType: ![[TY:[0-9]+]]
811
// CHECK-DAG: ![[TY]] = {{.*}}identifier: "$s4main1A_AA1BAA1DpXSpSgD"

0 commit comments

Comments
 (0)