mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Represent Swift errors as DW_TAG_thrown_type in DWARF
This allows the debugger to display them alongside the function's return value when finish-ing a function. rdar://problem/29481673
This commit is contained in:
@@ -697,7 +697,7 @@ IRGenDebugInfo::emitFunction(const SILDebugScope *DS, llvm::Function *Fn,
|
||||
llvm::DITemplateParameterArray TemplateParameters = nullptr;
|
||||
llvm::DISubprogram *Decl = nullptr;
|
||||
|
||||
// Various flags
|
||||
// Various flags.
|
||||
bool IsLocalToUnit = Fn ? Fn->hasInternalLinkage() : true;
|
||||
bool IsDefinition = true;
|
||||
bool IsOptimized = Opts.Optimize;
|
||||
@@ -722,9 +722,20 @@ IRGenDebugInfo::emitFunction(const SILDebugScope *DS, llvm::Function *Fn,
|
||||
== SILFunctionType::Representation::Block)
|
||||
Flags |= llvm::DINode::FlagAppleBlock;
|
||||
|
||||
// Get the throws information.
|
||||
llvm::DITypeArray Error = nullptr;
|
||||
if (FnTy)
|
||||
if (auto ErrorInfo = FnTy->getOptionalErrorResult()) {
|
||||
auto DTI = DebugTypeInfo::getFromTypeInfo(
|
||||
nullptr, nullptr, ErrorInfo->getType(),
|
||||
IGM.getTypeInfo(IGM.silConv.getSILType(*ErrorInfo)));
|
||||
Error = DBuilder.getOrCreateArray({getOrCreateType(DTI)}).get();
|
||||
}
|
||||
|
||||
// Construct the DISubprogram.
|
||||
llvm::DISubprogram *SP = DBuilder.createFunction(
|
||||
Scope, Name, LinkageName, File, Line, DIFnTy, IsLocalToUnit, IsDefinition,
|
||||
ScopeLine, Flags, IsOptimized, TemplateParameters, Decl);
|
||||
ScopeLine, Flags, IsOptimized, TemplateParameters, Decl, Error);
|
||||
|
||||
if (Fn && !Fn->isDeclaration())
|
||||
Fn->setSubprogram(SP);
|
||||
|
||||
34
test/DebugInfo/ErrorVar.swift
Normal file
34
test/DebugInfo/ErrorVar.swift
Normal file
@@ -0,0 +1,34 @@
|
||||
// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s
|
||||
// REQUIRES: CPU=i386
|
||||
class Obj {}
|
||||
|
||||
enum MyError : Error {
|
||||
case Simple
|
||||
case WithObj(Obj)
|
||||
}
|
||||
|
||||
// i386 does not pass swifterror in a register. To support debugging of the
|
||||
// thrown error we create a shadow stack location holding the address of the
|
||||
// location that holds the pointer to the error instead.
|
||||
func simple(_ placeholder: Int64) throws -> () {
|
||||
// CHECK: define {{.*}}void @_T06Errors6simpleys5Int64VKF(i64, %swift.refcounted* swiftself, %swift.error**)
|
||||
// CHECK: call void @llvm.dbg.declare
|
||||
// CHECK: call void @llvm.dbg.declare({{.*}}, metadata ![[ERROR:[0-9]+]], metadata ![[DEREF:[0-9]+]])
|
||||
// CHECK: ![[ERROR]] = !DILocalVariable(name: "$error", arg: 2,
|
||||
// CHECK-SAME: type: ![[ERRTY:.*]], flags: DIFlagArtificial)
|
||||
// CHECK: ![[ERRTY]] = !DICompositeType({{.*}}identifier: "_T0s5Error_pD"
|
||||
// CHECK: ![[DEREF]] = !DIExpression(DW_OP_deref)
|
||||
throw MyError.Simple
|
||||
}
|
||||
|
||||
func obj() throws -> () {
|
||||
throw MyError.WithObj(Obj())
|
||||
}
|
||||
|
||||
public func foo() {
|
||||
do {
|
||||
try simple(1)
|
||||
try obj()
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
@@ -1,34 +1,36 @@
|
||||
// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s
|
||||
// REQUIRES: CPU=i386
|
||||
class Obj {}
|
||||
public enum E : Error { case Err }
|
||||
|
||||
enum MyError : Error {
|
||||
case Simple
|
||||
case WithObj(Obj)
|
||||
// Function throws.
|
||||
public func throwError() throws { throw E.Err }
|
||||
// CHECK: !DISubprogram(name: "throwError", {{.*}}thrownTypes: ![[THROWN:.*]])
|
||||
// CHECK: ![[THROWN]] = !{![[ERROR:[0-9]+]]}
|
||||
// CHECK: ![[ERROR]] = !DICompositeType(tag: DW_TAG_structure_type,
|
||||
// CHECK-SAME: name: "Error"
|
||||
|
||||
|
||||
// Function rethrows.
|
||||
public func rethrow(fn : (() throws -> ())) rethrows { try fn() }
|
||||
// CHECK: !DISubprogram(name: "rethrow", {{.*}}thrownTypes: ![[THROWN:.*]])
|
||||
|
||||
public class C {
|
||||
// Initializer throws.
|
||||
init() throws { throw E.Err }
|
||||
// CHECK: !DISubprogram(name: "init", {{.*}}line: [[@LINE-1]],
|
||||
// CHECK-SAME: thrownTypes: ![[THROWN:.*]])
|
||||
|
||||
// Initializer rethrows.
|
||||
init(fn : (() throws -> ())) rethrows {
|
||||
// CHECK: !DISubprogram(name: "init", {{.*}}line: [[@LINE-1]],
|
||||
// CHECK-SAME: thrownTypes: ![[THROWN:.*]])
|
||||
try fn()
|
||||
}
|
||||
}
|
||||
|
||||
// i386 does not pass swifterror in a register. To support debugging of the
|
||||
// thrown error we create a shadow stack location holding the address of the
|
||||
// location that holds the pointer to the error instead.
|
||||
func simple(_ placeholder: Int64) throws -> () {
|
||||
// CHECK: define {{.*}}void @_T06Errors6simpleys5Int64VKF(i64, %swift.refcounted* swiftself, %swift.error**)
|
||||
// CHECK: call void @llvm.dbg.declare
|
||||
// CHECK: call void @llvm.dbg.declare({{.*}}, metadata ![[ERROR:[0-9]+]], metadata ![[DEREF:[0-9]+]])
|
||||
// CHECK: ![[ERROR]] = !DILocalVariable(name: "$error", arg: 2,
|
||||
// CHECK-SAME: type: ![[ERRTY:.*]], flags: DIFlagArtificial)
|
||||
// CHECK: ![[ERRTY]] = !DICompositeType({{.*}}identifier: "_T0s5Error_pD"
|
||||
// CHECK: ![[DEREF]] = !DIExpression(DW_OP_deref)
|
||||
throw MyError.Simple
|
||||
}
|
||||
|
||||
func obj() throws -> () {
|
||||
throw MyError.WithObj(Obj())
|
||||
}
|
||||
|
||||
public func foo() {
|
||||
do {
|
||||
try simple(1)
|
||||
try obj()
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
// Negative tests.
|
||||
// CHECK: !DISubprogram(name: "returnThrowing",
|
||||
// CHECK-NOT: thrownTypes:
|
||||
public func returnThrowing() -> (() throws -> ()) { return throwError }
|
||||
// CHECK: !DISubprogram(name: "takesThrowing",
|
||||
// CHECK-NOT: thrownTypes:
|
||||
public func takesThrowing(fn : (() throws -> ())) {}
|
||||
|
||||
Reference in New Issue
Block a user