[DebugInfo] Fix recursively generating debug info for same type

Debug Info generation already has a check to stop it from generating
debug info for a type with the same mangled name. However, most of the
code paths in debug info generation would not add the mangled name to
the cache while generation was not done. This patch fixes that so types
that are in-flight don't have their debug info generated twice.

rdar://142500619
This commit is contained in:
Augusto Noronha
2025-01-16 14:08:04 -08:00
parent 29bcd2caa0
commit aa6b5c2b63
2 changed files with 123 additions and 121 deletions

View File

@@ -1092,28 +1092,30 @@ private:
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) ||
UniqueID.starts_with(MANGLING_PREFIX_EMBEDDED_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;
}
@@ -1124,8 +1126,9 @@ private:
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;
@@ -1171,9 +1174,9 @@ private:
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()) {
@@ -1215,12 +1218,10 @@ private:
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);
@@ -1231,34 +1232,27 @@ private:
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> {
/// 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;
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();
@@ -1267,8 +1261,8 @@ createSpecializedStructOrClassType(NominalOrBoundGenericNominalType *Type,
auto DbgTy = DebugTypeInfo::getFromTypeInfo(
UnsubstitutedTy, IGM.getTypeInfoForUnlowered(UnsubstitutedTy), IGM);
Mangle::ASTMangler Mangler(IGM.Context);
std::string DeclTypeMangledName =
Mangler.mangleTypeForDebugger(UnsubstitutedTy->mapTypeOutOfContext(), {});
std::string DeclTypeMangledName = Mangler.mangleTypeForDebugger(
UnsubstitutedTy->mapTypeOutOfContext(), {});
if (DeclTypeMangledName == MangledName) {
return createUnsubstitutedGenericStructOrClassType(
DbgTy, Decl, UnsubstitutedTy, Scope, File, Line, Flags, nullptr,
@@ -1301,7 +1295,7 @@ createSpecializedStructOrClassType(NominalOrBoundGenericNominalType *Type,
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,
@@ -1319,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);
@@ -1373,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;
@@ -1437,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()) {
@@ -1655,13 +1637,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();
@@ -1720,12 +1698,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,

View File

@@ -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: "$eSpySo4S1_taGD"
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, {{.*}} identifier: "$eSpySo2S2VGD"