[DebugInfo] Fix infinite recursion when opaque return type is defined

inside function returning it

A stack overflow would happen when the compiler tried emitting debug
info for a function whose opaque return type was declared inside the
function itself. This fixes the issue by emitting a forward declaration
for the function before emitting it.

rdar://150313956

(cherry picked from commit c03831f70d)
This commit is contained in:
Augusto Noronha
2025-05-28 10:07:42 +09:00
parent 88f32b364e
commit 7b46d41823
2 changed files with 24 additions and 1 deletions

View File

@@ -979,7 +979,10 @@ private:
if (Scope)
return MainFile;
}
return cast<llvm::DIFile>(Scope);
if (Scope)
return cast<llvm::DIFile>(Scope);
return MainFile;
}
static unsigned getStorageSizeInBits(const llvm::DataLayout &DL,
@@ -3222,6 +3225,11 @@ IRGenDebugInfoImpl::emitFunction(const SILDebugScope *DS, llvm::Function *Fn,
Name = LinkageName;
}
llvm::DISubprogram *ReplaceableType = DBuilder.createTempFunctionFwdDecl(
Scope, Name, LinkageName, File, Line, /*Type=*/nullptr, ScopeLine);
auto FwdDecl = llvm::TempDISubprogram(ReplaceableType);
ScopeCache[DS] = llvm::TrackingMDNodeRef(FwdDecl.get());
CanSILFunctionType FnTy = getFunctionType(SILTy);
auto Params = Opts.DebugInfoLevel > IRGenDebugInfoLevel::LineTables
? createParameterTypes(SILTy)
@@ -3321,6 +3329,7 @@ IRGenDebugInfoImpl::emitFunction(const SILDebugScope *DS, llvm::Function *Fn,
if (!DS)
return nullptr;
DBuilder.replaceTemporary(std::move(FwdDecl), SP);
ScopeCache[DS] = llvm::TrackingMDNodeRef(SP);
return SP;
}

View File

@@ -0,0 +1,14 @@
// RUN: %target-swift-frontend -primary-file %s -emit-ir -g -o - | %FileCheck %s
protocol TheProtocol {
}
// CHECK: ![[FUNC_ID:[0-9]+]] = distinct !DISubprogram(name: "theFunction",
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "TheType", scope: ![[FUNC_ID]]
func theFunction() -> some TheProtocol {
struct TheType: TheProtocol {
}
return TheType()
}
theFunction()