[Debug info] Emit bound generic class type parameters when emitting AST types

This relands commit 45d4648bdb while ensuring that
sanityCheckCachedType uses the exact same condition (now factored into a helper
function) as createType() to determine whether a type is sized or not.

rdar://143833326
This commit is contained in:
Adrian Prantl
2025-01-30 17:31:31 -08:00
parent feaa2f724e
commit 91b6162f25
4 changed files with 88 additions and 74 deletions

View File

@@ -1197,7 +1197,26 @@ private:
Scope, Name, File, Line, SizeInBits, AlignInBits, Flags, DerivedFrom,
DBuilder.getOrCreateArray(Elements), RuntimeLang, nullptr, UniqueID);
DBuilder.replaceTemporary(std::move(FwdDecl), DITy);
return DITy;;
return DITy;
}
std::pair<bool, Type>
getUnsubstituedType(Type Ty, StringRef MangledName) {
if (!Ty)
return {false,{}};
// Go from Pair<Int, Double> to Pair<T, U>.
auto *Decl = Ty->getNominalOrBoundGenericNominal();
if (!Decl)
return {false, {}};
// Go from Pair<Int, Double> to Pair<T, U>.
Type InterfaceTy = Decl->getDeclaredInterfaceType();
Type UnsubstitutedTy = Decl->mapTypeIntoContext(InterfaceTy);
Mangle::ASTMangler Mangler(IGM.Context);
std::string DeclTypeMangledName = Mangler.mangleTypeForDebugger(
UnsubstitutedTy->mapTypeOutOfContext(), {});
bool IsUnsubstituted = (DeclTypeMangledName == MangledName);
return {IsUnsubstituted, UnsubstitutedTy};
}
llvm::DIType *
@@ -1206,28 +1225,24 @@ private:
unsigned SizeInBits, unsigned AlignInBits,
llvm::DIScope *Scope, llvm::DIFile *File,
unsigned Line, llvm::DINode::DIFlags Flags) {
auto UnsubstitutedTy = Decl->getDeclaredInterfaceType();
UnsubstitutedTy = Decl->mapTypeIntoContext(UnsubstitutedTy);
auto DbgTy = DebugTypeInfo::getFromTypeInfo(
auto [IsUnsubstituted, UnsubstitutedTy] =
getUnsubstituedType(EnumTy, MangledName);
auto UnsubstitutedDbgTy = DebugTypeInfo::getFromTypeInfo(
UnsubstitutedTy, IGM.getTypeInfoForUnlowered(UnsubstitutedTy), IGM);
Mangle::ASTMangler Mangler(IGM.Context);
std::string DeclTypeMangledName = Mangler.mangleTypeForDebugger(
UnsubstitutedTy->mapTypeOutOfContext(), {});
if (DeclTypeMangledName == MangledName) {
return createUnsubstitutedVariantType(DbgTy, Decl, MangledName, Scope,
File, 0, Flags);
}
if (IsUnsubstituted)
return createUnsubstitutedVariantType(UnsubstitutedDbgTy, Decl,
MangledName, Scope, File, 0, Flags);
StringRef Name = Decl->getName().str();
auto FwdDecl = createTemporaryReplaceableForwardDecl(
EnumTy, Scope, File, Line, SizeInBits, AlignInBits, Flags, MangledName,
Name);
// Force the creation of the unsubstituted type, don't create it
// directly so it goes through all the caching/verification logic.
auto unsubstitutedDbgTy = getOrCreateType(DbgTy);
auto UnsubstitutedDITy = getOrCreateType(UnsubstitutedDbgTy);
auto DIType = createOpaqueStruct(
Scope, "", File, 0, SizeInBits, AlignInBits, Flags, MangledName,
collectGenericParams(EnumTy), unsubstitutedDbgTy);
collectGenericParams(EnumTy), UnsubstitutedDITy);
DBuilder.replaceTemporary(std::move(FwdDecl), DIType);
return DIType;
}
@@ -1235,7 +1250,7 @@ private:
/// Create a DICompositeType from a specialized struct. A specialized type
/// is a generic type, or a child type whose parent is generic.
llvm::DIType *createSpecializedStructOrClassType(
NominalOrBoundGenericNominalType *Type, NominalTypeDecl *Decl,
NominalOrBoundGenericNominalType *Type,
llvm::DIScope *Scope, llvm::DIFile *File, unsigned Line,
unsigned SizeInBits, unsigned AlignInBits, llvm::DINode::DIFlags Flags,
StringRef MangledName, bool IsClass = false) {
@@ -1249,28 +1264,26 @@ private:
// When emitting debug information for a type such as Pair<Int, Double>,
// emit a description of all the fields for Pair<T, U>, and emit the regular
// debug information for Pair<Int, Double>.
auto *Decl = Type->getNominalOrBoundGenericNominal();
if (!Decl)
return nullptr;
StringRef Name = Decl->getName().str();
auto FwdDecl = createTemporaryReplaceableForwardDecl(
Type, Scope, File, Line, SizeInBits, AlignInBits, Flags, MangledName,
Name);
// Go from Pair<Int, Double> to Pair<T, U>.
auto UnsubstitutedTy = Decl->getDeclaredInterfaceType();
UnsubstitutedTy = Decl->mapTypeIntoContext(UnsubstitutedTy);
auto DbgTy = DebugTypeInfo::getFromTypeInfo(
UnsubstitutedTy, IGM.getTypeInfoForUnlowered(UnsubstitutedTy), IGM);
Mangle::ASTMangler Mangler(IGM.Context);
std::string DeclTypeMangledName = Mangler.mangleTypeForDebugger(
UnsubstitutedTy->mapTypeOutOfContext(), {});
if (DeclTypeMangledName == MangledName) {
auto [IsUnsubstitued, UnsubstitutedType] =
getUnsubstituedType(Type, MangledName);
auto UnsubstitutedDbgTy = DebugTypeInfo::getFromTypeInfo(
UnsubstitutedType, IGM.getTypeInfoForUnlowered(UnsubstitutedType), IGM);
if (IsUnsubstitued)
return createUnsubstitutedGenericStructOrClassType(
DbgTy, Decl, UnsubstitutedTy, Scope, File, Line, Flags, nullptr,
llvm::dwarf::DW_LANG_Swift, DeclTypeMangledName);
}
UnsubstitutedDbgTy, Decl, UnsubstitutedType, Scope, File, Line, Flags,
nullptr, llvm::dwarf::DW_LANG_Swift, MangledName);
// Force the creation of the unsubstituted type, don't create it
// directly so it goes through all the caching/verification logic.
auto UnsubstitutedType = getOrCreateType(DbgTy);
auto UnsubstitutedDITy = getOrCreateType(UnsubstitutedDbgTy);
if (auto *ClassTy = llvm::dyn_cast<BoundGenericClassType>(Type)) {
auto SuperClassTy = ClassTy->getSuperclass();
@@ -1280,19 +1293,15 @@ private:
llvm::DIType *SuperClassDITy = getOrCreateType(SuperClassDbgTy);
assert(SuperClassDITy && "getOrCreateType should never return null!");
DBuilder.createInheritance(UnsubstitutedType, SuperClassDITy, 0, 0,
DBuilder.createInheritance(UnsubstitutedDITy, SuperClassDITy, 0, 0,
llvm::DINode::FlagZero);
}
auto *OpaqueType = createPointerSizedStruct(
Scope, Decl ? Decl->getNameStr() : MangledName, File, 0, Flags,
MangledName, UnsubstitutedType);
return OpaqueType;
}
auto *OpaqueType = createOpaqueStruct(
Scope, "", File, Line, SizeInBits, AlignInBits, Flags, MangledName,
collectGenericParams(Type), UnsubstitutedType);
auto *OpaqueType =
createOpaqueStruct(Scope, Decl ? Decl->getNameStr() : "", File, Line,
SizeInBits, AlignInBits, Flags, MangledName,
collectGenericParams(Type), UnsubstitutedDITy);
DBuilder.replaceTemporary(std::move(FwdDecl), OpaqueType);
return OpaqueType;
}
@@ -1865,7 +1874,7 @@ private:
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes) {
if (StructTy->isSpecialized())
return createSpecializedStructOrClassType(
StructTy, Decl, Scope, L.File, L.Line, SizeInBits, AlignInBits,
StructTy, Scope, L.File, L.Line, SizeInBits, AlignInBits,
Flags, MangledName);
return createStructType(DbgTy, Decl, StructTy, Scope, L.File, L.Line,
SizeInBits, AlignInBits, Flags, nullptr,
@@ -1898,7 +1907,7 @@ private:
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes) {
if (ClassTy->isSpecialized())
return createSpecializedStructOrClassType(
ClassTy, Decl, Scope, L.File, L.Line, SizeInBits, AlignInBits,
ClassTy, Scope, L.File, L.Line, SizeInBits, AlignInBits,
Flags, MangledName);
auto *DIType = createStructType(
@@ -1964,7 +1973,7 @@ private:
unsigned FwdDeclLine = 0;
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes)
return createSpecializedStructOrClassType(
StructTy, Decl, Scope, L.File, L.Line, SizeInBits, AlignInBits,
StructTy, Scope, L.File, L.Line, SizeInBits, AlignInBits,
Flags, MangledName);
return createOpaqueStructWithSizedContainer(
@@ -1977,20 +1986,9 @@ private:
auto *ClassTy = BaseTy->castTo<BoundGenericClassType>();
auto *Decl = ClassTy->getDecl();
auto L = getFileAndLocation(Decl);
unsigned FwdDeclLine = 0;
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes)
return createSpecializedStructOrClassType(
ClassTy, Decl, Scope, L.File, L.Line, SizeInBits, AlignInBits,
Flags, MangledName);
// TODO: We may want to peek at Decl->isObjC() and set this
// attribute accordingly.
assert(SizeInBits ==
CI.getTargetInfo().getPointerWidth(clang::LangAS::Default));
return createPointerSizedStruct(
Scope, Decl ? Decl->getNameStr() : MangledName, L.File, FwdDeclLine,
Flags, MangledName, SpecificationOf);
return createSpecializedStructOrClassType(ClassTy, Scope, L.File,
L.Line, SizeInBits, AlignInBits,
Flags, MangledName);
}
case TypeKind::Pack:
@@ -2174,8 +2172,14 @@ private:
AliasedTy, DbgTy.getAlignment(), DbgTy.hasDefaultAlignment(),
/* IsMetadataType = */ false, DbgTy.isFixedBuffer(),
DbgTy.getNumExtraInhabitants());
return DBuilder.createTypedef(getOrCreateType(AliasedDbgTy), MangledName,
L.File, 0, Scope);
auto *TypeDef = DBuilder.createTypedef(getOrCreateType(AliasedDbgTy),
MangledName, L.File, 0, Scope);
// Bound generic types don't reference their type parameters in ASTTypes
// mode, so we need to artificially keep typealiases alive, since they can
// appear in reflection metadata.
if (Opts.DebugInfoLevel < IRGenDebugInfoLevel::DwarfTypes)
DBuilder.retainType(TypeDef);
return TypeDef;
}
case TypeKind::Locatable: {
@@ -2269,10 +2273,15 @@ private:
// so skip the sanity check.
if (CachedType->isTemporary())
return true;
if (!isa<llvm::DICompositeType>(CachedType))
return true;
bool IsUnsubstituted =
getUnsubstituedType(DbgTy.getType(), getMangledName(DbgTy)).first;
std::optional<uint64_t> SizeInBits;
std::optional<CompletedDebugTypeInfo> CompletedDbgTy = completeType(DbgTy);
if (CompletedDbgTy)
SizeInBits = CompletedDbgTy->getSizeInBits();
if (!IsUnsubstituted)
if (auto CompletedDbgTy = completeType(DbgTy))
SizeInBits = CompletedDbgTy->getSizeInBits();
unsigned CachedSizeInBits = getSizeInBits(CachedType);
if (SizeInBits && CachedSizeInBits != *SizeInBits) {
// Note that CachedSizeInBits && !SizeInBits may happen and is benign,
@@ -2511,6 +2520,7 @@ private:
// winning over a full definition.
auto *FwdDecl = DBuilder.createReplaceableCompositeType(
llvm::dwarf::DW_TAG_structure_type, MangledName, Scope, 0, 0,
llvm::dwarf::DW_LANG_Swift);
FwdDeclTypes.emplace_back(
std::piecewise_construct, std::make_tuple(MangledName),

View File

@@ -351,14 +351,14 @@ func testBlocksWithGenerics(hba: HasBlockArray) -> Any {
// CHECK: attributes [[NOUNWIND]] = { nounwind memory(read) }
// CHECK: ![[SWIFT_NAME_ALIAS_VAR]] = !DILocalVariable(name: "obj", arg: 1, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[SWIFT_NAME_ALIAS_TYPE:[0-9]+]])
// CHECK: ![[LET_SWIFT_NAME_ALIAS_TYPE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[SWIFT_NAME_ALIAS_TYPE:[0-9]+]])
// CHECK: ![[SWIFT_NAME_ALIAS_TYPE]] = !DIDerivedType(tag: DW_TAG_typedef, name: "$sSo14SwiftNameAliasaD", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, baseType: !{{[0-9]+}})
// CHECK-DAG: ![[SWIFT_NAME_ALIAS_VAR]] = !DILocalVariable(name: "obj", arg: 1, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 328, type: ![[LET_SWIFT_NAME_ALIAS_TYPE:[0-9]+]])
// CHECK-DAG: ![[LET_SWIFT_NAME_ALIAS_TYPE]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[SWIFT_NAME_ALIAS_TYPE:[0-9]+]])
// CHECK-DAG: ![[SWIFT_NAME_ALIAS_TYPE]] = !DIDerivedType(tag: DW_TAG_typedef, name: "$sSo14SwiftNameAliasaD", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, baseType: !{{[0-9]+}})
// CHECK: ![[SWIFT_GENERIC_NAME_ALIAS_VAR]] = !DILocalVariable(name: "generic_obj", arg: 1, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[LET_SWIFT_GENERIC_NAME_ALIAS_TYPE:[0-9]+]])
// CHECK: ![[LET_SWIFT_GENERIC_NAME_ALIAS_TYPE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[SWIFT_GENERIC_NAME_ALIAS_TYPE:[0-9]+]])
// CHECK: ![[SWIFT_GENERIC_NAME_ALIAS_TYPE]] = !DIDerivedType(tag: DW_TAG_typedef, name: "$sSo21SwiftGenericNameAliasaySo8NSNumberCGD", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, baseType: !{{[0-9]+}})
// CHECK-DAG: ![[SWIFT_GENERIC_NAME_ALIAS_VAR]] = !DILocalVariable(name: "generic_obj", arg: 1, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[LET_SWIFT_GENERIC_NAME_ALIAS_TYPE:[0-9]+]])
// CHECK-DAG: ![[LET_SWIFT_GENERIC_NAME_ALIAS_TYPE]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[SWIFT_GENERIC_NAME_ALIAS_TYPE:[0-9]+]])
// CHECK-DAG: ![[SWIFT_GENERIC_NAME_ALIAS_TYPE]] = !DIDerivedType(tag: DW_TAG_typedef, name: "$sSo21SwiftGenericNameAliasaySo8NSNumberCGD", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, baseType: !{{[0-9]+}})
// CHECK: ![[SWIFT_CONSTR_GENERIC_NAME_ALIAS_VAR]] = !DILocalVariable(name: "constr_generic_obj", arg: 1, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[LET_SWIFT_CONSTR_GENERIC_NAME_ALIAS_TYPE:[0-9]+]])
// CHECK: ![[LET_SWIFT_CONSTR_GENERIC_NAME_ALIAS_TYPE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[SWIFT_CONSTR_GENERIC_NAME_ALIAS_TYPE:[0-9]+]])
// CHECK: ![[SWIFT_CONSTR_GENERIC_NAME_ALIAS_TYPE]] = !DIDerivedType(tag: DW_TAG_typedef, name: "$sSo27SwiftConstrGenericNameAliasaySo8NSNumberCGD", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, baseType: !{{[0-9]+}})
// CHECK-DAG: ![[SWIFT_CONSTR_GENERIC_NAME_ALIAS_VAR]] = !DILocalVariable(name: "constr_generic_obj", arg: 1, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[LET_SWIFT_CONSTR_GENERIC_NAME_ALIAS_TYPE:[0-9]+]])
// CHECK-DAG: ![[LET_SWIFT_CONSTR_GENERIC_NAME_ALIAS_TYPE]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[SWIFT_CONSTR_GENERIC_NAME_ALIAS_TYPE:[0-9]+]])
// CHECK-DAG: ![[SWIFT_CONSTR_GENERIC_NAME_ALIAS_TYPE]] = !DIDerivedType(tag: DW_TAG_typedef, name: "$sSo27SwiftConstrGenericNameAliasaySo8NSNumberCGD", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, baseType: !{{[0-9]+}})

View File

@@ -12,7 +12,6 @@ public let s = S<Int>(t: 0)
// CHECK: ![[INTPARAM]] = !DITemplateTypeParameter(type: ![[INT:[0-9]+]])
// CHECK: ![[INT]] = !DICompositeType(tag: DW_TAG_structure_type, {{.*}}identifier: "$sSiD"
// DWARF: !DICompositeType(tag: DW_TAG_structure_type,
// DWARF-SAME: templateParams: ![[PARAMS:[0-9]+]]
// DWARF-SAME: identifier: "$s18BoundGenericStruct1SVySiGD"
@@ -40,10 +39,7 @@ public let inner = S2<Double>.Inner(t:4.2)
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "$s18BoundGenericStruct2S2VyxGD",
// CHECK-SAME: flags: DIFlagFwdDecl, runtimeLang: DW_LANG_Swift)
// DWARF: !DICompositeType(tag: DW_TAG_structure_type, scope: ![[SCOPE1:[0-9]+]],
// DWARF-SAME: size: 64, {{.*}}, templateParams: ![[PARAMS2:[0-9]+]], identifier: "$s18BoundGenericStruct2S2V5InnerVySd_GD"
// DWARF-SAME: specification: ![[SPECIFICATION:[0-9]+]]
// DWARF: !DICompositeType(tag: DW_TAG_structure_type, name: "Inner", scope: ![[SCOPE1:[0-9]+]],{{.*}} size: 64, {{.*}}, templateParams: ![[PARAMS2:[0-9]+]], identifier: "$s18BoundGenericStruct2S2V5InnerVySd_GD",{{.*}} specification: ![[SPECIFICATION:[0-9]+]]
// DWARF: ![[SCOPE1]] = !DICompositeType(tag: DW_TAG_structure_type, name: "$s18BoundGenericStruct2S2VyxGD",
// DWARF: ![[PARAMS2]] = !{![[PARAMS3:[0-9]+]]}

View File

@@ -0,0 +1,8 @@
// RUN: %target-swift-frontend %s -emit-ir -parse-as-library -module-name a -g -o - | %FileCheck %s
// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "$s1a10LocalAliasaD", {{.*}}baseType: ![[BASETY:[0-9]+]]
// CHECK: ![[BASETY]]{{.*}}$sSbD
public class MyClass<A, B> {}
public typealias LocalAlias = Bool
public typealias ClassAlias = MyClass<LocalAlias, Bool>
public func use(cls: ClassAlias?) {}