Skip to content

[DebugInfo] Fix recursively generating debug info for same type #79033

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

Closed
Closed
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
230 changes: 103 additions & 127 deletions lib/IRGen/IRGenDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1092,27 +1092,30 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
return DITy;
}

llvm::TempDIType createStructForwardDecl(
DebugTypeInfo DbgTy, NominalTypeDecl *Decl, llvm::DIScope *Scope,
llvm::DIFile *File, unsigned Line, unsigned SizeInBits,
llvm::DINode::DIFlags Flags, StringRef UniqueID, StringRef Name) {
// Forward declare this first because types may be recursive.
llvm::TempDICompositeType FwdDecl(DBuilder.createReplaceableCompositeType(
llvm::dwarf::DW_TAG_structure_type, Name, Scope, File, Line,
llvm::dwarf::DW_LANG_Swift, SizeInBits, 0, Flags, UniqueID));

/// Creates a temporary replaceable forward decl to protect against recursion.
llvm::TempDIType createTemporaryReplaceableForwardDecl(
TypeBase *Type, llvm::DIScope *Scope, llvm::DIFile *File, unsigned Line,
unsigned SizeInBits, unsigned AlignInBits, llvm::DINode::DIFlags Flags,
StringRef MangledName, StringRef Name) {
#ifndef NDEBUG
if (UniqueID.empty())
if (MangledName.empty())
assert(!Name.empty() &&
"no mangled name and no human readable name given");
else
assert((UniqueID.starts_with("_T") ||
UniqueID.starts_with(MANGLING_PREFIX_STR)) &&
assert(swift::Demangle::isMangledName(MangledName) &&
"UID is not a mangled name");
#endif
auto ReplaceableType = DBuilder.createReplaceableCompositeType(
llvm::dwarf::DW_TAG_structure_type, "", Scope, File, Line,
llvm::dwarf::DW_LANG_Swift, SizeInBits, AlignInBits, Flags,
MangledName);
auto FwdDecl = llvm::TempDIType(ReplaceableType);

auto TH = llvm::TrackingMDNodeRef(FwdDecl.get());
DITypeCache[DbgTy.getType()] = TH;
DITypeCache[Type] = TH;
if (auto UID = ReplaceableType->getRawIdentifier())
DIRefMap[UID] = llvm::TrackingMDNodeRef(TH);

return FwdDecl;
}

Expand All @@ -1123,8 +1126,9 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
llvm::DINode::DIFlags Flags, llvm::DIType *DerivedFrom,
unsigned RuntimeLang, StringRef UniqueID) {
StringRef Name = Decl->getName().str();
auto FwdDecl = createStructForwardDecl(DbgTy, Decl, Scope, File, Line,
SizeInBits, Flags, UniqueID, Name);
auto FwdDecl = createTemporaryReplaceableForwardDecl(
DbgTy.getType(), Scope, File, Line, SizeInBits, AlignInBits, Flags,
UniqueID, Name);
// Collect the members.
SmallVector<llvm::Metadata *, 16> Elements;
unsigned OffsetInBits = 0;
Expand Down Expand Up @@ -1170,9 +1174,9 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
unsigned SizeInBits = 0;
unsigned AlignInBits = 0;
StringRef Name = Decl->getName().str();
auto FwdDecl = createStructForwardDecl(DbgTy, Decl, Scope, File, Line,
SizeInBits, Flags, UniqueID, Name);

auto FwdDecl = createTemporaryReplaceableForwardDecl(
DbgTy.getType(), Scope, File, Line, SizeInBits, AlignInBits, Flags,
UniqueID, Name);
// Collect the members.
SmallVector<llvm::Metadata *, 16> Elements;
for (VarDecl *VD : Decl->getStoredProperties()) {
Expand Down Expand Up @@ -1214,12 +1218,10 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
return createUnsubstitutedVariantType(DbgTy, Decl, MangledName, Scope,
File, 0, Flags);
}
auto FwdDecl = llvm::TempDIType(DBuilder.createReplaceableCompositeType(
llvm::dwarf::DW_TAG_structure_type, "", Scope, File, 0,
llvm::dwarf::DW_LANG_Swift, 0, 0, llvm::DINode::FlagZero, MangledName));

auto TH = llvm::TrackingMDNodeRef(FwdDecl.get());
DITypeCache[EnumTy] = TH;
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);
Expand All @@ -1230,78 +1232,71 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
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, llvm::DIScope *Scope,
llvm::DIFile *File, unsigned Line,
unsigned SizeInBits, unsigned AlignInBits,
llvm::DINode::DIFlags Flags,
StringRef MangledName,
bool IsClass = false) {
// To emit debug info of the DwarfTypes level for generic types, the strategy
// is to emit a description of all the fields for the type with archetypes,
// and still the same debug info as the ASTTypes level for the specialized
// type. For example, given:
// struct Pair<T, U> {
// let t: T
// let u: U
// }
// 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 FwdDecl = llvm::TempDIType(DBuilder.createReplaceableCompositeType(
llvm::dwarf::DW_TAG_structure_type, "", Scope, File, Line,
llvm::dwarf::DW_LANG_Swift, SizeInBits, 0, Flags, MangledName));

auto TH = llvm::TrackingMDNodeRef(FwdDecl.get());
DITypeCache[Type] = TH;

// 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;
std::string DeclTypeMangledName =
Mangler.mangleTypeForDebugger(UnsubstitutedTy->mapTypeOutOfContext(), {});
if (DeclTypeMangledName == MangledName) {
return createUnsubstitutedGenericStructOrClassType(
DbgTy, Decl, UnsubstitutedTy, Scope, File, Line, Flags, nullptr,
llvm::dwarf::DW_LANG_Swift, DeclTypeMangledName);
}
// 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);

if (auto *ClassTy = llvm::dyn_cast<BoundGenericClassType>(Type)) {
auto SuperClassTy = ClassTy->getSuperclass();
if (SuperClassTy) {
auto SuperClassDbgTy = DebugTypeInfo::getFromTypeInfo(
SuperClassTy, IGM.getTypeInfoForUnlowered(SuperClassTy), IGM);

llvm::DIType *SuperClassDITy = getOrCreateType(SuperClassDbgTy);
assert(SuperClassDITy && "getOrCreateType should never return null!");
DBuilder.createInheritance(UnsubstitutedType, SuperClassDITy, 0, 0,
llvm::DINode::FlagZero);
}

auto *OpaqueType = createPointerSizedStruct(
Scope, Decl ? Decl->getNameStr() : MangledName, File, 0, Flags,
MangledName, UnsubstitutedType);
/// 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,
llvm::DIScope *Scope, llvm::DIFile *File, unsigned Line,
unsigned SizeInBits, unsigned AlignInBits, llvm::DINode::DIFlags Flags,
StringRef MangledName, bool IsClass = false) {
// To emit debug info of the DwarfTypes level for generic types, the
// strategy is to emit a description of all the fields for the type with
// archetypes, and still the same debug info as the ASTTypes level for the
// specialized type. For example, given: struct Pair<T, U> {
// let t: T
// let u: U
// }
// 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>.
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;
std::string DeclTypeMangledName = Mangler.mangleTypeForDebugger(
UnsubstitutedTy->mapTypeOutOfContext(), {});
if (DeclTypeMangledName == MangledName) {
return createUnsubstitutedGenericStructOrClassType(
DbgTy, Decl, UnsubstitutedTy, Scope, File, Line, Flags, nullptr,
llvm::dwarf::DW_LANG_Swift, DeclTypeMangledName);
}
// 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);

if (auto *ClassTy = llvm::dyn_cast<BoundGenericClassType>(Type)) {
auto SuperClassTy = ClassTy->getSuperclass();
if (SuperClassTy) {
auto SuperClassDbgTy = DebugTypeInfo::getFromTypeInfo(
SuperClassTy, IGM.getTypeInfoForUnlowered(SuperClassTy), IGM);

llvm::DIType *SuperClassDITy = getOrCreateType(SuperClassDbgTy);
assert(SuperClassDITy && "getOrCreateType should never return null!");
DBuilder.createInheritance(UnsubstitutedType, 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);
DBuilder.replaceTemporary(std::move(FwdDecl), OpaqueType);
return OpaqueType;
}

auto *OpaqueType = createOpaqueStruct(
Scope, "", File, Line, SizeInBits, AlignInBits, Flags, MangledName,
collectGenericParams(Type), UnsubstitutedType);
DBuilder.replaceTemporary(std::move(FwdDecl), OpaqueType);
return OpaqueType;
}

/// Create debug information for an enum with a raw type (enum E : Int {}).
llvm::DICompositeType *createRawEnumType(CompletedDebugTypeInfo DbgTy,
EnumDecl *Decl,
Expand All @@ -1318,13 +1313,9 @@ createSpecializedStructOrClassType(NominalOrBoundGenericNominalType *Type,
// Default, since Swift doesn't allow specifying a custom alignment.
unsigned AlignInBits = 0;

llvm::TempDICompositeType FwdDecl(DBuilder.createReplaceableCompositeType(
llvm::dwarf::DW_TAG_enumeration_type, MangledName, Scope, File, Line,
llvm::dwarf::DW_LANG_Swift, SizeInBits, AlignInBits, Flags,
MangledName));

auto TH = llvm::TrackingMDNodeRef(FwdDecl.get());
DITypeCache[DbgTy.getType()] = TH;
auto FwdDecl = createTemporaryReplaceableForwardDecl(
DbgTy.getType(), Scope, File, Line, SizeInBits, AlignInBits, Flags,
MangledName, Name);

auto RawType = Decl->getRawType();
auto &TI = IGM.getTypeInfoForUnlowered(RawType);
Expand Down Expand Up @@ -1372,14 +1363,10 @@ createSpecializedStructOrClassType(NominalOrBoundGenericNominalType *Type,

// A variant part should actually be a child to a DW_TAG_structure_type
// according to the DWARF spec.
llvm::TempDICompositeType FwdDecl(DBuilder.createReplaceableCompositeType(
llvm::dwarf::DW_TAG_structure_type, MangledName, Scope, File, Line,
llvm::dwarf::DW_LANG_Swift, SizeInBits, AlignInBits, Flags,
MangledName));

auto TH = llvm::TrackingMDNodeRef(FwdDecl.get());
DITypeCache[DbgTy.getType()] = TH;

auto FwdDecl = createTemporaryReplaceableForwardDecl(
DbgTy.getType(), Scope, File, Line, SizeInBits, AlignInBits, Flags,
MangledName, Name);
SmallVector<llvm::Metadata *, 16> Elements;
for (auto *ElemDecl : Decl->getAllElements()) {
std::optional<CompletedDebugTypeInfo> ElemDbgTy;
Expand Down Expand Up @@ -1436,13 +1423,9 @@ createSpecializedStructOrClassType(NominalOrBoundGenericNominalType *Type,
unsigned AlignInBits = 0;
// A variant part should actually be a child to a DW_TAG_structure_type
// according to the DWARF spec.
llvm::TempDICompositeType FwdDecl(DBuilder.createReplaceableCompositeType(
llvm::dwarf::DW_TAG_structure_type, MangledName, Scope, File, Line,
llvm::dwarf::DW_LANG_Swift, SizeInBits, AlignInBits, Flags,
MangledName));

auto TH = llvm::TrackingMDNodeRef(FwdDecl.get());
DITypeCache[DbgTy.getType()] = TH;
auto FwdDecl = createTemporaryReplaceableForwardDecl(
DbgTy.getType(), Scope, File, Line, SizeInBits, AlignInBits, Flags,
MangledName, Name);

SmallVector<llvm::Metadata *, 16> Elements;
for (auto *ElemDecl : Decl->getAllElements()) {
Expand Down Expand Up @@ -1649,13 +1632,9 @@ createSpecializedStructOrClassType(NominalOrBoundGenericNominalType *Type,
unsigned SizeInBits, unsigned AlignInBits,
llvm::DINode::DIFlags Flags,
StringRef MangledName) {
llvm::TempDICompositeType FwdDecl(DBuilder.createReplaceableCompositeType(
llvm::dwarf::DW_TAG_subroutine_type, MangledName, Scope, MainFile, 0,
llvm::dwarf::DW_LANG_Swift, SizeInBits, AlignInBits, Flags,
MangledName));

auto TH = llvm::TrackingMDNodeRef(FwdDecl.get());
DITypeCache[DbgTy.getType()] = TH;
auto FwdDecl = createTemporaryReplaceableForwardDecl(
DbgTy.getType(), Scope, MainFile, 0, SizeInBits, AlignInBits, Flags,
MangledName, MangledName);

CanSILFunctionType FunTy;
TypeBase *BaseTy = DbgTy.getType();
Expand Down Expand Up @@ -1714,12 +1693,9 @@ createSpecializedStructOrClassType(NominalOrBoundGenericNominalType *Type,
}
// FIXME: assert that SizeInBits == OffsetInBits.

llvm::TempDICompositeType FwdDecl(DBuilder.createReplaceableCompositeType(
llvm::dwarf::DW_TAG_structure_type, MangledName, Scope, MainFile, 0,
llvm::dwarf::DW_LANG_Swift, SizeInBits, AlignInBits, Flags,
MangledName));

DITypeCache[DbgTy.getType()] = llvm::TrackingMDNodeRef(FwdDecl.get());
auto FwdDecl = createTemporaryReplaceableForwardDecl(
DbgTy.getType(), Scope, MainFile, 0, SizeInBits, AlignInBits, Flags,
MangledName, MangledName);

auto DITy = DBuilder.createStructType(
Scope, MangledName, MainFile, 0, SizeInBits, AlignInBits, Flags,
Expand Down
27 changes: 27 additions & 0 deletions test/DebugInfo/embedded-recur-c-types.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// RUN: %empty-directory(%t)
// RUN: %{python} %utils/split_file.py -o %t %s

// RUN: %target-swift-frontend %t/Main.swift -g -target %target-cpu-apple-macos14 -import-bridging-header %t/BridgingHeader.h -enable-experimental-feature Embedded -wmo -emit-ir -o - | %FileCheck %s

// REQUIRES: swift_in_compiler
// REQUIRES: executable_test
// REQUIRES: OS=macosx
// REQUIRES: embedded_stdlib
// REQUIRES: swift_feature_Embedded

// BEGIN BridgingHeader.h
#pragma once
typedef struct S2 S2_t;
typedef struct S1 {
struct S2 *other;
} S1_t;
typedef struct S2 {
S1_t *producer_pool;
} S2_t;

// BEGIN Main.swift

public var v: UnsafeMutablePointer<S1_t>? = nil

// CHECK: !DICompositeType(tag: DW_TAG_structure_type, {{.*}} identifier: "$sSpySo4S1_taGD"
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, {{.*}} identifier: "$sSpySo2S2VGD"