Skip to content

Commit 9311d7a

Browse files
committed
[DebugInfo] Generate debug info for specialized types
Specialized types are generic types, or types whose parent is specialized. IRGenDebugInfo was previously mistankenly emitting debug info for nominal specialized types as if they regular nominal types, which caused problems as that code path does not handle references to generic parameters. (cherry picked from commit ae5e341)
1 parent ae9e957 commit 9311d7a

File tree

3 files changed

+176
-77
lines changed

3 files changed

+176
-77
lines changed

lib/IRGen/GenEnum.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5887,8 +5887,10 @@ namespace {
58875887
std::optional<SpareBitsMaskInfo> calculateSpareBitsMask() const override {
58885888
SpareBitVector spareBits;
58895889
for (auto enumCase : getElementsWithPayload()) {
5890-
cast<FixedTypeInfo>(enumCase.ti)
5891-
->applyFixedSpareBitsMask(IGM, spareBits);
5890+
if (auto fixedTI = llvm::dyn_cast<FixedTypeInfo>(enumCase.ti))
5891+
fixedTI->applyFixedSpareBitsMask(IGM, spareBits);
5892+
else
5893+
return {};
58925894
}
58935895
// Trim leading/trailing zero bytes, then pad to a multiple of 32 bits
58945896
llvm::APInt bits = spareBits.asAPInt();

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 142 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,23 +1157,12 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
11571157
return DITy;;
11581158
}
11591159

1160-
llvm::DIType *createFullDebugInfoGenericForStructOrClassType(
1161-
BoundGenericType *Type, NominalTypeDecl *Decl, llvm::DIScope *Scope,
1162-
llvm::DIFile *File, unsigned Line, unsigned SizeInBits,
1163-
unsigned AlignInBits, llvm::DINode::DIFlags Flags,
1164-
StringRef MangledName, bool IsClass = false) {
1165-
// To emit full debug info for generic types, the strategy is to emit
1166-
// full debug info for the type with archetypes, and still emit opaque
1167-
// debug information for the specialized type. For example, given:
1168-
// struct Pair<T, U> {
1169-
// let t : T
1170-
// let u: U
1171-
// }
1172-
// When emitting debug information for a type such as Pair<Int, Double>,
1173-
// emit full debug info for Pair<T, U>, and emit the regular debug
1174-
// information for Pair<Int, Double>.
1175-
1176-
// Go from Pair<Int, Double> to Pair<T, U>.
1160+
llvm::DIType *
1161+
createSpecializedEnumType(NominalOrBoundGenericNominalType *EnumTy,
1162+
EnumDecl *Decl, StringRef MangledName,
1163+
unsigned SizeInBits, unsigned AlignInBits,
1164+
llvm::DIScope *Scope, llvm::DIFile *File,
1165+
unsigned Line, llvm::DINode::DIFlags Flags) {
11771166
auto UnsubstitutedTy = Decl->getDeclaredInterfaceType();
11781167
UnsubstitutedTy = Decl->mapTypeIntoContext(UnsubstitutedTy);
11791168

@@ -1183,39 +1172,99 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
11831172
std::string DeclTypeMangledName = Mangler.mangleTypeForDebugger(
11841173
UnsubstitutedTy->mapTypeOutOfContext(), {});
11851174
if (DeclTypeMangledName == MangledName) {
1186-
return createUnsubstitutedGenericStructOrClassType(
1187-
DbgTy, Decl, UnsubstitutedTy, Scope, File, Line, SizeInBits,
1188-
AlignInBits, Flags, nullptr, llvm::dwarf::DW_LANG_Swift,
1189-
DeclTypeMangledName);
1175+
return createUnsubstitutedVariantType(DbgTy, Decl, MangledName,
1176+
SizeInBits, AlignInBits, Scope,
1177+
File, 0, Flags);
11901178
}
1179+
auto FwdDecl = llvm::TempDIType(DBuilder.createReplaceableCompositeType(
1180+
llvm::dwarf::DW_TAG_structure_type, "", Scope, File, 0,
1181+
llvm::dwarf::DW_LANG_Swift, 0, 0, llvm::DINode::FlagZero, MangledName));
1182+
1183+
auto TH = llvm::TrackingMDNodeRef(FwdDecl.get());
1184+
DITypeCache[EnumTy] = TH;
11911185
// Force the creation of the unsubstituted type, don't create it
11921186
// directly so it goes through all the caching/verification logic.
1193-
auto UnsubstitutedType = getOrCreateType(DbgTy);
1194-
1195-
if (auto *ClassTy = llvm::dyn_cast<BoundGenericClassType>(Type)) {
1196-
auto SuperClassTy = ClassTy->getSuperclass();
1197-
if (SuperClassTy) {
1198-
auto SuperClassDbgTy = DebugTypeInfo::getFromTypeInfo(
1199-
SuperClassTy, IGM.getTypeInfoForUnlowered(SuperClassTy), IGM);
1200-
1201-
llvm::DIType *SuperClassDITy = getOrCreateType(SuperClassDbgTy);
1202-
assert(SuperClassDITy && "getOrCreateType should never return null!");
1203-
DBuilder.createInheritance(UnsubstitutedType, SuperClassDITy, 0, 0,
1204-
llvm::DINode::FlagZero);
1205-
}
1206-
1207-
auto *OpaqueType = createPointerSizedStruct(
1208-
Scope, Decl ? Decl->getNameStr() : MangledName, File, 0, Flags,
1209-
MangledName, UnsubstitutedType);
1210-
return OpaqueType;
1211-
}
1212-
1213-
auto *OpaqueType = createOpaqueStruct(
1214-
Scope, "", File, Line, SizeInBits, AlignInBits, Flags, MangledName,
1215-
collectGenericParams(Type), UnsubstitutedType);
1187+
auto unsubstitutedDbgTy = getOrCreateType(DbgTy);
1188+
auto DIType = createOpaqueStruct(
1189+
Scope, "", File, 0, SizeInBits, AlignInBits, Flags, MangledName,
1190+
collectGenericParams(EnumTy), unsubstitutedDbgTy);
1191+
DBuilder.replaceTemporary(std::move(FwdDecl), DIType);
1192+
return DIType;
1193+
}
1194+
1195+
/// Create a DICompositeType from a specialized struct. A specialized type
1196+
/// is a generic type, or a child type whose parent is generic.
1197+
llvm::DIType *
1198+
createSpecializedStructOrClassType(NominalOrBoundGenericNominalType *Type,
1199+
NominalTypeDecl *Decl, llvm::DIScope *Scope,
1200+
llvm::DIFile *File, unsigned Line,
1201+
unsigned SizeInBits, unsigned AlignInBits,
1202+
llvm::DINode::DIFlags Flags,
1203+
StringRef MangledName,
1204+
bool IsClass = false) {
1205+
// To emit debug info of the DwarfTypes level for generic types, the strategy
1206+
// is to emit a description of all the fields for the type with archetypes,
1207+
// and still the same debug info as the ASTTypes level for the specialized
1208+
// type. For example, given:
1209+
// struct Pair<T, U> {
1210+
// let t: T
1211+
// let u: U
1212+
// }
1213+
// When emitting debug information for a type such as Pair<Int, Double>,
1214+
// emit a description of all the fields for Pair<T, U>, and emit the regular
1215+
// debug information for Pair<Int, Double>.
1216+
1217+
auto FwdDecl = llvm::TempDIType(DBuilder.createReplaceableCompositeType(
1218+
llvm::dwarf::DW_TAG_structure_type, "", Scope, File, Line,
1219+
llvm::dwarf::DW_LANG_Swift, SizeInBits, 0, Flags, MangledName));
1220+
1221+
auto TH = llvm::TrackingMDNodeRef(FwdDecl.get());
1222+
DITypeCache[Type] = TH;
1223+
1224+
// Go from Pair<Int, Double> to Pair<T, U>.
1225+
auto UnsubstitutedTy = Decl->getDeclaredInterfaceType();
1226+
UnsubstitutedTy = Decl->mapTypeIntoContext(UnsubstitutedTy);
1227+
1228+
auto DbgTy = DebugTypeInfo::getFromTypeInfo(
1229+
UnsubstitutedTy, IGM.getTypeInfoForUnlowered(UnsubstitutedTy), IGM);
1230+
Mangle::ASTMangler Mangler;
1231+
std::string DeclTypeMangledName =
1232+
Mangler.mangleTypeForDebugger(UnsubstitutedTy->mapTypeOutOfContext(), {});
1233+
if (DeclTypeMangledName == MangledName) {
1234+
return createUnsubstitutedGenericStructOrClassType(
1235+
DbgTy, Decl, UnsubstitutedTy, Scope, File, Line, SizeInBits,
1236+
AlignInBits, Flags, nullptr, llvm::dwarf::DW_LANG_Swift,
1237+
DeclTypeMangledName);
1238+
}
1239+
// Force the creation of the unsubstituted type, don't create it
1240+
// directly so it goes through all the caching/verification logic.
1241+
auto UnsubstitutedType = getOrCreateType(DbgTy);
1242+
1243+
if (auto *ClassTy = llvm::dyn_cast<BoundGenericClassType>(Type)) {
1244+
auto SuperClassTy = ClassTy->getSuperclass();
1245+
if (SuperClassTy) {
1246+
auto SuperClassDbgTy = DebugTypeInfo::getFromTypeInfo(
1247+
SuperClassTy, IGM.getTypeInfoForUnlowered(SuperClassTy), IGM);
1248+
1249+
llvm::DIType *SuperClassDITy = getOrCreateType(SuperClassDbgTy);
1250+
assert(SuperClassDITy && "getOrCreateType should never return null!");
1251+
DBuilder.createInheritance(UnsubstitutedType, SuperClassDITy, 0, 0,
1252+
llvm::DINode::FlagZero);
1253+
}
1254+
1255+
auto *OpaqueType = createPointerSizedStruct(
1256+
Scope, Decl ? Decl->getNameStr() : MangledName, File, 0, Flags,
1257+
MangledName, UnsubstitutedType);
12161258
return OpaqueType;
12171259
}
12181260

1261+
auto *OpaqueType = createOpaqueStruct(
1262+
Scope, "", File, Line, SizeInBits, AlignInBits, Flags, MangledName,
1263+
collectGenericParams(Type), UnsubstitutedType);
1264+
DBuilder.replaceTemporary(std::move(FwdDecl), OpaqueType);
1265+
return OpaqueType;
1266+
}
1267+
12191268
/// Create debug information for an enum with a raw type (enum E : Int {}).
12201269
llvm::DICompositeType *createRawEnumType(CompletedDebugTypeInfo DbgTy,
12211270
EnumDecl *Decl,
@@ -1441,17 +1490,29 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
14411490
/// Collect the type parameters of a bound generic type. This is needed to
14421491
/// anchor any typedefs that may appear in parameters so they can be
14431492
/// resolved in the debugger without needing to query the Swift module.
1444-
llvm::DINodeArray collectGenericParams(BoundGenericType *BGT) {
1493+
llvm::DINodeArray
1494+
collectGenericParams(NominalOrBoundGenericNominalType *BGT) {
1495+
1496+
// Collect the generic args from the type and its parent.
1497+
std::vector<Type> GenericArgs;
1498+
Type CurrentType = BGT;
1499+
while (CurrentType && CurrentType->getAnyNominal()) {
1500+
if (auto *BGT = llvm::dyn_cast<BoundGenericType>(CurrentType))
1501+
GenericArgs.insert(GenericArgs.end(), BGT->getGenericArgs().begin(),
1502+
BGT->getGenericArgs().end());
1503+
CurrentType = CurrentType->getNominalParent();
1504+
}
1505+
14451506
SmallVector<llvm::Metadata *, 16> TemplateParams;
1446-
for (auto Param : BGT->getGenericArgs()) {
1507+
for (auto Arg : GenericArgs) {
14471508
DebugTypeInfo ParamDebugType;
14481509
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes)
1449-
// For full debug info don't generate just a forward declaration for
1450-
// the generic type parameters.
1510+
// For the DwarfTypes level don't generate just a forward declaration
1511+
// for the generic type parameters.
14511512
ParamDebugType = DebugTypeInfo::getFromTypeInfo(
1452-
Param, IGM.getTypeInfoForUnlowered(Param), IGM);
1513+
Arg, IGM.getTypeInfoForUnlowered(Arg), IGM);
14531514
else
1454-
ParamDebugType = DebugTypeInfo::getForwardDecl(Param);
1515+
ParamDebugType = DebugTypeInfo::getForwardDecl(Arg);
14551516

14561517
TemplateParams.push_back(DBuilder.createTemplateTypeParameter(
14571518
TheCU, "", getOrCreateType(ParamDebugType), false));
@@ -1625,7 +1686,6 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
16251686
createMemberType(DbgTy, "", OffsetInBits, Scope, MainFile, Flags));
16261687
}
16271688
// FIXME: assert that SizeInBits == OffsetInBits.
1628-
SizeInBits = OffsetInBits;
16291689

16301690
auto FwdDecl = llvm::TempDINode(DBuilder.createReplaceableCompositeType(
16311691
llvm::dwarf::DW_TAG_structure_type, MangledName, Scope, MainFile, 0,
@@ -1786,10 +1846,15 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
17861846
// don't want a whitespace change to an secondary file trigger a
17871847
// recompilation of the debug info of a primary source file.
17881848
unsigned FwdDeclLine = 0;
1789-
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes)
1849+
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes) {
1850+
if (StructTy->isSpecialized())
1851+
return createSpecializedStructOrClassType(
1852+
StructTy, Decl, Scope, L.File, L.Line, SizeInBits, AlignInBits,
1853+
Flags, MangledName);
17901854
return createStructType(DbgTy, Decl, StructTy, Scope, L.File, L.Line,
17911855
SizeInBits, AlignInBits, Flags, nullptr,
17921856
llvm::dwarf::DW_LANG_Swift, MangledName);
1857+
}
17931858
StringRef Name = Decl->getName().str();
17941859
if (!SizeInBitsOrNull)
17951860
return DBuilder.createForwardDecl(
@@ -1814,6 +1879,11 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
18141879
assert(SizeInBits ==
18151880
CI.getTargetInfo().getPointerWidth(clang::LangAS::Default));
18161881
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes) {
1882+
if (ClassTy->isSpecialized())
1883+
return createSpecializedStructOrClassType(
1884+
ClassTy, Decl, Scope, L.File, L.Line, SizeInBits, AlignInBits,
1885+
Flags, MangledName);
1886+
18171887
auto *DIType = createStructType(
18181888
DbgTy, Decl, ClassTy, Scope, File, L.Line, SizeInBits, AlignInBits,
18191889
Flags, nullptr, llvm::dwarf::DW_LANG_Swift, MangledName);
@@ -1875,7 +1945,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
18751945
auto L = getFileAndLocation(Decl);
18761946
unsigned FwdDeclLine = 0;
18771947
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes)
1878-
return createFullDebugInfoGenericForStructOrClassType(
1948+
return createSpecializedStructOrClassType(
18791949
StructTy, Decl, Scope, L.File, L.Line, SizeInBits, AlignInBits,
18801950
Flags, MangledName);
18811951

@@ -1892,7 +1962,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
18921962
unsigned FwdDeclLine = 0;
18931963

18941964
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes)
1895-
return createFullDebugInfoGenericForStructOrClassType(
1965+
return createSpecializedStructOrClassType(
18961966
ClassTy, Decl, Scope, L.File, L.Line, SizeInBits, AlignInBits,
18971967
Flags, MangledName);
18981968

@@ -2011,10 +2081,16 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
20112081
auto *Decl = EnumTy->getDecl();
20122082
auto L = getFileAndLocation(Decl);
20132083
unsigned FwdDeclLine = 0;
2014-
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes)
2084+
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes) {
2085+
if (EnumTy->isSpecialized())
2086+
return createSpecializedEnumType(EnumTy, Decl, MangledName,
2087+
SizeInBits, AlignInBits, Scope, File,
2088+
FwdDeclLine, Flags);
2089+
20152090
if (CompletedDbgTy)
20162091
return createEnumType(*CompletedDbgTy, Decl, MangledName, AlignInBits,
20172092
Scope, L.File, L.Line, Flags);
2093+
}
20182094
return createOpaqueStruct(Scope, Decl->getName().str(), L.File,
20192095
FwdDeclLine, SizeInBits, AlignInBits, Flags,
20202096
MangledName);
@@ -2027,25 +2103,13 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
20272103
unsigned FwdDeclLine = 0;
20282104

20292105
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes) {
2030-
auto UnsubstitutedTy = Decl->getDeclaredInterfaceType();
2031-
UnsubstitutedTy = Decl->mapTypeIntoContext(UnsubstitutedTy);
2032-
2033-
auto DbgTy = DebugTypeInfo::getFromTypeInfo(
2034-
UnsubstitutedTy, IGM.getTypeInfoForUnlowered(UnsubstitutedTy), IGM);
2035-
Mangle::ASTMangler Mangler;
2036-
std::string DeclTypeMangledName = Mangler.mangleTypeForDebugger(
2037-
UnsubstitutedTy->mapTypeOutOfContext(), {});
2038-
if (DeclTypeMangledName == MangledName) {
2039-
return createUnsubstitutedVariantType(DbgTy, Decl, MangledName,
2040-
SizeInBits, AlignInBits, Scope, File,
2041-
FwdDeclLine, Flags);
2042-
}
2043-
// Force the creation of the unsubstituted type, don't create it
2044-
// directly so it goes through all the caching/verification logic.
2045-
auto unsubstitutedDbgTy = getOrCreateType(DbgTy);
2046-
return createOpaqueStruct(
2047-
Scope, "", L.File, FwdDeclLine, SizeInBits, AlignInBits, Flags,
2048-
MangledName, collectGenericParams(EnumTy), unsubstitutedDbgTy);
2106+
if (EnumTy->isSpecialized())
2107+
return createSpecializedEnumType(EnumTy, Decl, MangledName,
2108+
SizeInBits, AlignInBits, Scope, File,
2109+
FwdDeclLine, Flags);
2110+
if (CompletedDbgTy)
2111+
return createEnumType(*CompletedDbgTy, Decl, MangledName, AlignInBits,
2112+
Scope, L.File, L.Line, Flags);
20492113
}
20502114
return createOpaqueStructWithSizedContainer(
20512115
Scope, Decl->getName().str(), L.File, FwdDeclLine, SizeInBits,
@@ -2184,6 +2248,10 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
21842248
#ifndef NDEBUG
21852249
/// Verify that the size of this type matches the one of the cached type.
21862250
bool sanityCheckCachedType(DebugTypeInfo DbgTy, llvm::DIType *CachedType) {
2251+
// If this is a temporary, we're in the middle of creating a recursive type,
2252+
// so skip the sanity check.
2253+
if (CachedType->isTemporary())
2254+
return true;
21872255
if (DbgTy.isForwardDecl())
21882256
return true;
21892257
auto CompletedDbgTy = CompletedDebugTypeInfo::getFromTypeInfo(

test/DebugInfo/BoundGenericStruct.swift

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,35 @@ public let s = S<Int>(t: 0)
2525
// DWARF: !DICompositeType(tag: DW_TAG_structure_type, name: "S",
2626
// DWARF-SAME: identifier: "$s18BoundGenericStruct1SVyxGD")
2727
// DWARF: !DIDerivedType(tag: DW_TAG_member, name: "t"
28-
// DWARF: !DICompositeType(tag: DW_TAG_structure_type, name: "$sxD"
28+
// DWARF: ![[GENERIC_PARAM_TYPE:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "$sxD"
2929

3030

31+
public struct S2<T> {
32+
public struct Inner {
33+
let t: T
34+
}
35+
}
36+
public let inner = S2<Double>.Inner(t:4.2)
37+
38+
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Inner",
39+
// CHECK-SAME: size: 64, {{.*}}identifier: "$s18BoundGenericStruct2S2V5InnerVySd_GD")
40+
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "$s18BoundGenericStruct2S2VyxGD",
41+
// CHECK-SAME: flags: DIFlagFwdDecl, runtimeLang: DW_LANG_Swift)
42+
43+
// DWARF: !DICompositeType(tag: DW_TAG_structure_type, scope: ![[SCOPE1:[0-9]+]],
44+
// DWARF-SAME: size: 64, {{.*}}, templateParams: ![[PARAMS2:[0-9]+]], identifier: "$s18BoundGenericStruct2S2V5InnerVySd_GD"
45+
// DWARF-SAME: specification_of: ![[SPECIFICATION:[0-9]+]]
46+
47+
// DWARF: ![[SCOPE1]] = !DICompositeType(tag: DW_TAG_structure_type, name: "$s18BoundGenericStruct2S2VyxGD",
48+
49+
// DWARF: ![[PARAMS2]] = !{![[PARAMS3:[0-9]+]]}
50+
// DWARF: ![[PARAMS3]] = !DITemplateTypeParameter(type: ![[PARAMS4:[0-9]+]])
51+
// DWARF: ![[PARAMS4]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Double",
52+
// DWARF-SAME: size: 64, {{.*}}runtimeLang: DW_LANG_Swift, identifier: "$sSdD")
53+
54+
// DWARF: [[SPECIFICATION]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Inner",
55+
// DWARF-SAME: elements: ![[ELEMENTS1:[0-9]+]], runtimeLang: DW_LANG_Swift, identifier: "$s18BoundGenericStruct2S2V5InnerVyx_GD")
56+
57+
// DWARF: ![[ELEMENTS1]] = !{![[ELEMENTS2:[0-9]+]]}
58+
59+
// DWARF: ![[ELEMENTS2]] = !DIDerivedType(tag: DW_TAG_member, name: "t", scope: !27, file: !3, baseType: ![[GENERIC_PARAM_TYPE]])

0 commit comments

Comments
 (0)