Skip to content

[Debug info] Emit bound generic class type parameters when emitting A… #79085

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/swift/RemoteInspection/TypeLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ class ArrayTypeInfo : public TypeInfo {
int *extraInhabitantIndex) const override;

BitMask getSpareBits(TypeConverter &TC, bool &hasAddrOnly) const override;

const TypeInfo *getElementTypeInfo() const { return ElementTI; }
static bool classof(const TypeInfo *TI) {
return TI->getKind() == TypeInfoKind::Array;
}
Expand Down
7 changes: 0 additions & 7 deletions lib/IRGen/DebugTypeInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,19 +179,12 @@ TypeDecl *DebugTypeInfo::getDecl() const {
return nullptr;
}

bool DebugTypeInfo::isForwardDecl() const {
return isNull() || (!isa<TypeAliasType>(getType()));
}

#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void DebugTypeInfo::dump() const {
llvm::errs() << "[";
llvm::errs() << "Alignment " << Align.getValue() << "] ";
if (auto *Type = getType())
Type->dump(llvm::errs());

if (isForwardDecl())
llvm::errs() << "forward-declared\n";
}
#endif

Expand Down
1 change: 0 additions & 1 deletion lib/IRGen/DebugTypeInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ class DebugTypeInfo {

Alignment getAlignment() const { return Align; }
bool isNull() const { return !Type; }
bool isForwardDecl() const;
bool isMetadataType() const { return IsMetadataType; }
bool hasDefaultAlignment() const { return DefaultAlignment; }
bool isFixedBuffer() const { return IsFixedBuffer; }
Expand Down
130 changes: 70 additions & 60 deletions lib/IRGen/IRGenDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,26 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
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 *
Expand All @@ -1206,36 +1225,32 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
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;
}

/// 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) {
Expand All @@ -1249,28 +1264,26 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
// 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();
Expand All @@ -1280,19 +1293,15 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {

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;
}
Expand Down Expand Up @@ -1865,7 +1874,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
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,
Expand Down Expand Up @@ -1898,7 +1907,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
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(
Expand Down Expand Up @@ -1964,7 +1973,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
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(
Expand All @@ -1977,20 +1986,9 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
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:
Expand Down Expand Up @@ -2174,8 +2172,14 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
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: {
Expand Down Expand Up @@ -2269,10 +2273,15 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
// 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,
Expand Down Expand Up @@ -2511,6 +2520,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
// 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),
Expand Down
18 changes: 9 additions & 9 deletions test/ClangImporter/objc_ir.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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]+}})
6 changes: 1 addition & 5 deletions test/DebugInfo/BoundGenericStruct.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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]+]]}
Expand Down
8 changes: 8 additions & 0 deletions test/DebugInfo/typealias_indirect.swift
Original file line number Diff line number Diff line change
@@ -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?) {}