Add support for DW_TAG_thrown_type.

For Swift we would like to be able to encode the error types that a
function may throw, so the debugger can display them alongside the
function's return value when finish-ing a function.

DWARF defines DW_TAG_thrown_type (intended to be used for C++ throw()
declarations) that is a perfect fit for this purpose. This patch wires
up support for DW_TAG_thrown_type in LLVM by adding a list of thrown
types to DISubprogram.

To offset the cost of the extra pointer, there is a follow-up patch
that turns DISubprogram into a variable-length node.

rdar://problem/29481673

Differential Revision: https://reviews.llvm.org/D32559

llvm-svn: 301489
This commit is contained in:
Adrian Prantl 2017-04-26 22:56:44 +00:00
parent 7cdb7b7867
commit 23c2febb59
17 changed files with 272 additions and 136 deletions

View File

@ -577,15 +577,14 @@ namespace llvm {
/// These flags are used to emit dwarf attributes.
/// \param isOptimized True if optimization is ON.
/// \param TParams Function template parameters.
DISubprogram *createFunction(DIScope *Scope, StringRef Name,
StringRef LinkageName, DIFile *File,
unsigned LineNo, DISubroutineType *Ty,
bool isLocalToUnit, bool isDefinition,
unsigned ScopeLine,
DINode::DIFlags Flags = DINode::FlagZero,
bool isOptimized = false,
DITemplateParameterArray TParams = nullptr,
DISubprogram *Decl = nullptr);
/// \param ThrownTypes Exception types this function may throw.
DISubprogram *createFunction(
DIScope *Scope, StringRef Name, StringRef LinkageName, DIFile *File,
unsigned LineNo, DISubroutineType *Ty, bool isLocalToUnit,
bool isDefinition, unsigned ScopeLine,
DINode::DIFlags Flags = DINode::FlagZero, bool isOptimized = false,
DITemplateParameterArray TParams = nullptr,
DISubprogram *Decl = nullptr, DITypeArray ThrownTypes = nullptr);
/// Identical to createFunction,
/// except that the resulting DbgNode is meant to be RAUWed.
@ -595,7 +594,7 @@ namespace llvm {
bool isDefinition, unsigned ScopeLine,
DINode::DIFlags Flags = DINode::FlagZero, bool isOptimized = false,
DITemplateParameterArray TParams = nullptr,
DISubprogram *Decl = nullptr);
DISubprogram *Decl = nullptr, DITypeArray ThrownTypes = nullptr);
/// Create a new descriptor for the specified C++ method.
/// See comments in \a DISubprogram* for descriptions of these fields.
@ -619,13 +618,15 @@ namespace llvm {
/// This flags are used to emit dwarf attributes.
/// \param isOptimized True if optimization is ON.
/// \param TParams Function template parameters.
/// \param ThrownTypes Exception types this function may throw.
DISubprogram *createMethod(
DIScope *Scope, StringRef Name, StringRef LinkageName, DIFile *File,
unsigned LineNo, DISubroutineType *Ty, bool isLocalToUnit,
bool isDefinition, unsigned Virtuality = 0, unsigned VTableIndex = 0,
int ThisAdjustment = 0, DIType *VTableHolder = nullptr,
DINode::DIFlags Flags = DINode::FlagZero, bool isOptimized = false,
DITemplateParameterArray TParams = nullptr);
DITemplateParameterArray TParams = nullptr,
DITypeArray ThrownTypes = nullptr);
/// This creates new descriptor for a namespace with the specified
/// parent scope.

View File

@ -1509,14 +1509,14 @@ class DISubprogram : public DILocalScope {
unsigned VirtualIndex, int ThisAdjustment, DIFlags Flags,
bool IsOptimized, DICompileUnit *Unit,
DITemplateParameterArray TemplateParams, DISubprogram *Declaration,
DILocalVariableArray Variables, StorageType Storage,
bool ShouldCreate = true) {
DILocalVariableArray Variables, DITypeArray ThrownTypes,
StorageType Storage, bool ShouldCreate = true) {
return getImpl(Context, Scope, getCanonicalMDString(Context, Name),
getCanonicalMDString(Context, LinkageName), File, Line, Type,
IsLocalToUnit, IsDefinition, ScopeLine, ContainingType,
Virtuality, VirtualIndex, ThisAdjustment, Flags, IsOptimized,
Unit, TemplateParams.get(), Declaration, Variables.get(),
Storage, ShouldCreate);
ThrownTypes.get(), Storage, ShouldCreate);
}
static DISubprogram *
getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name,
@ -1525,15 +1525,16 @@ class DISubprogram : public DILocalScope {
Metadata *ContainingType, unsigned Virtuality, unsigned VirtualIndex,
int ThisAdjustment, DIFlags Flags, bool IsOptimized, Metadata *Unit,
Metadata *TemplateParams, Metadata *Declaration, Metadata *Variables,
StorageType Storage, bool ShouldCreate = true);
Metadata *ThrownTypes, StorageType Storage, bool ShouldCreate = true);
TempDISubprogram cloneImpl() const {
return getTemporary(
getContext(), getScope(), getName(), getLinkageName(), getFile(),
getLine(), getType(), isLocalToUnit(), isDefinition(), getScopeLine(),
getContainingType(), getVirtuality(), getVirtualIndex(),
getThisAdjustment(), getFlags(), isOptimized(), getUnit(),
getTemplateParams(), getDeclaration(), getVariables());
return getTemporary(getContext(), getScope(), getName(), getLinkageName(),
getFile(), getLine(), getType(), isLocalToUnit(),
isDefinition(), getScopeLine(), getContainingType(),
getVirtuality(), getVirtualIndex(), getThisAdjustment(),
getFlags(), isOptimized(), getUnit(),
getTemplateParams(), getDeclaration(), getVariables(),
getThrownTypes());
}
public:
@ -1546,11 +1547,12 @@ public:
bool IsOptimized, DICompileUnit *Unit,
DITemplateParameterArray TemplateParams = nullptr,
DISubprogram *Declaration = nullptr,
DILocalVariableArray Variables = nullptr),
DILocalVariableArray Variables = nullptr,
DITypeArray ThrownTypes = nullptr),
(Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit,
IsDefinition, ScopeLine, ContainingType, Virtuality,
VirtualIndex, ThisAdjustment, Flags, IsOptimized, Unit,
TemplateParams, Declaration, Variables))
TemplateParams, Declaration, Variables, ThrownTypes))
DEFINE_MDNODE_GET(
DISubprogram,
(Metadata * Scope, MDString *Name, MDString *LinkageName, Metadata *File,
@ -1558,10 +1560,12 @@ public:
unsigned ScopeLine, Metadata *ContainingType, unsigned Virtuality,
unsigned VirtualIndex, int ThisAdjustment, DIFlags Flags,
bool IsOptimized, Metadata *Unit, Metadata *TemplateParams = nullptr,
Metadata *Declaration = nullptr, Metadata *Variables = nullptr),
Metadata *Declaration = nullptr, Metadata *Variables = nullptr,
Metadata *ThrownTypes = nullptr),
(Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition,
ScopeLine, ContainingType, Virtuality, VirtualIndex, ThisAdjustment,
Flags, IsOptimized, Unit, TemplateParams, Declaration, Variables))
Flags, IsOptimized, Unit, TemplateParams, Declaration, Variables,
ThrownTypes))
TempDISubprogram clone() const { return cloneImpl(); }
@ -1626,9 +1630,7 @@ public:
DICompileUnit *getUnit() const {
return cast_or_null<DICompileUnit>(getRawUnit());
}
void replaceUnit(DICompileUnit *CU) {
replaceOperandWith(7, CU);
}
void replaceUnit(DICompileUnit *CU) { replaceOperandWith(7, CU); }
DITemplateParameterArray getTemplateParams() const {
return cast_or_null<MDTuple>(getRawTemplateParams());
}
@ -1638,6 +1640,9 @@ public:
DILocalVariableArray getVariables() const {
return cast_or_null<MDTuple>(getRawVariables());
}
DITypeArray getThrownTypes() const {
return cast_or_null<MDTuple>(getRawThrownTypes());
}
Metadata *getRawScope() const { return getOperand(1); }
Metadata *getRawType() const { return getOperand(5); }
@ -1646,6 +1651,7 @@ public:
Metadata *getRawTemplateParams() const { return getOperand(8); }
Metadata *getRawDeclaration() const { return getOperand(9); }
Metadata *getRawVariables() const { return getOperand(10); }
Metadata *getRawThrownTypes() const { return getOperand(11); }
/// Check if this subprogram describes the given function.
///

View File

@ -4071,7 +4071,7 @@ bool LLParser::ParseDICompileUnit(MDNode *&Result, bool IsDistinct) {
/// virtuality: DW_VIRTUALTIY_pure_virtual,
/// virtualIndex: 10, thisAdjustment: 4, flags: 11,
/// isOptimized: false, templateParams: !4, declaration: !5,
/// variables: !6)
/// variables: !6, thrownTypes: !7)
bool LLParser::ParseDISubprogram(MDNode *&Result, bool IsDistinct) {
auto Loc = Lex.getLoc();
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
@ -4093,7 +4093,8 @@ bool LLParser::ParseDISubprogram(MDNode *&Result, bool IsDistinct) {
OPTIONAL(unit, MDField, ); \
OPTIONAL(templateParams, MDField, ); \
OPTIONAL(declaration, MDField, ); \
OPTIONAL(variables, MDField, );
OPTIONAL(variables, MDField, ); \
OPTIONAL(thrownTypes, MDField, );
PARSE_MD_FIELDS();
#undef VISIT_MD_FIELDS
@ -4103,12 +4104,12 @@ bool LLParser::ParseDISubprogram(MDNode *&Result, bool IsDistinct) {
"missing 'distinct', required for !DISubprogram when 'isDefinition'");
Result = GET_OR_DISTINCT(
DISubprogram, (Context, scope.Val, name.Val, linkageName.Val, file.Val,
line.Val, type.Val, isLocal.Val, isDefinition.Val,
scopeLine.Val, containingType.Val, virtuality.Val,
virtualIndex.Val, thisAdjustment.Val, flags.Val,
isOptimized.Val, unit.Val, templateParams.Val,
declaration.Val, variables.Val));
DISubprogram,
(Context, scope.Val, name.Val, linkageName.Val, file.Val, line.Val,
type.Val, isLocal.Val, isDefinition.Val, scopeLine.Val,
containingType.Val, virtuality.Val, virtualIndex.Val, thisAdjustment.Val,
flags.Val, isOptimized.Val, unit.Val, templateParams.Val,
declaration.Val, variables.Val, thrownTypes.Val));
return false;
}

View File

@ -1298,7 +1298,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
break;
}
case bitc::METADATA_SUBPROGRAM: {
if (Record.size() < 18 || Record.size() > 20)
if (Record.size() < 18 || Record.size() > 21)
return error("Invalid record");
IsDistinct =
@ -1314,29 +1314,31 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
unsigned Offset = Record.size() >= 19 ? 1 : 0;
bool HasFn = Offset && !HasUnit;
bool HasThisAdj = Record.size() >= 20;
bool HasThrownTypes = Record.size() >= 21;
DISubprogram *SP = GET_OR_DISTINCT(
DISubprogram, (Context,
getDITypeRefOrNull(Record[1]), // scope
getMDString(Record[2]), // name
getMDString(Record[3]), // linkageName
getMDOrNull(Record[4]), // file
Record[5], // line
getMDOrNull(Record[6]), // type
Record[7], // isLocal
Record[8], // isDefinition
Record[9], // scopeLine
getDITypeRefOrNull(Record[10]), // containingType
Record[11], // virtuality
Record[12], // virtualIndex
HasThisAdj ? Record[19] : 0, // thisAdjustment
static_cast<DINode::DIFlags>(Record[13] // flags
),
Record[14], // isOptimized
HasUnit ? CUorFn : nullptr, // unit
getMDOrNull(Record[15 + Offset]), // templateParams
getMDOrNull(Record[16 + Offset]), // declaration
getMDOrNull(Record[17 + Offset]) // variables
));
DISubprogram,
(Context,
getDITypeRefOrNull(Record[1]), // scope
getMDString(Record[2]), // name
getMDString(Record[3]), // linkageName
getMDOrNull(Record[4]), // file
Record[5], // line
getMDOrNull(Record[6]), // type
Record[7], // isLocal
Record[8], // isDefinition
Record[9], // scopeLine
getDITypeRefOrNull(Record[10]), // containingType
Record[11], // virtuality
Record[12], // virtualIndex
HasThisAdj ? Record[19] : 0, // thisAdjustment
static_cast<DINode::DIFlags>(Record[13]), // flags
Record[14], // isOptimized
HasUnit ? CUorFn : nullptr, // unit
getMDOrNull(Record[15 + Offset]), // templateParams
getMDOrNull(Record[16 + Offset]), // declaration
getMDOrNull(Record[17 + Offset]), // variables
HasThrownTypes ? getMDOrNull(Record[20]) : nullptr // thrownTypes
));
MetadataList.assignValue(SP, NextMetadataNo);
NextMetadataNo++;

View File

@ -1608,6 +1608,7 @@ void ModuleBitcodeWriter::writeDISubprogram(const DISubprogram *N,
Record.push_back(VE.getMetadataOrNullID(N->getDeclaration()));
Record.push_back(VE.getMetadataOrNullID(N->getVariables().get()));
Record.push_back(N->getThisAdjustment());
Record.push_back(VE.getMetadataOrNullID(N->getThrownTypes().get()));
Stream.EmitRecord(bitc::METADATA_SUBPROGRAM, Record, Abbrev);
Record.clear();

View File

@ -662,6 +662,14 @@ void DwarfUnit::addTemplateParams(DIE &Buffer, DINodeArray TParams) {
}
}
/// Add thrown types.
void DwarfUnit::addThrownTypes(DIE &Die, DINodeArray ThrownTypes) {
for (const auto *Ty : ThrownTypes) {
DIE &TT = createAndAddDIE(dwarf::DW_TAG_thrown_type, Die);
addType(TT, cast<DIType>(Ty));
}
}
DIE *DwarfUnit::getOrCreateContextDIE(const DIScope *Context) {
if (!Context || isa<DIFile>(Context))
return &getUnitDie();
@ -1249,6 +1257,8 @@ void DwarfUnit::applySubprogramAttributes(const DISubprogram *SP, DIE &SPDie,
constructSubprogramArguments(SPDie, Args);
}
addThrownTypes(SPDie, SP->getThrownTypes());
if (SP->isArtificial())
addFlag(SPDie, dwarf::DW_AT_artificial);

View File

@ -230,6 +230,9 @@ public:
/// Add template parameters in buffer.
void addTemplateParams(DIE &Buffer, DINodeArray TParams);
/// Add thrown types.
void addThrownTypes(DIE &Die, DINodeArray ThrownTypes);
// FIXME: Should be reformulated in terms of addComplexAddress.
/// Start with the address based on the location provided, and generate the
/// DWARF information necessary to find the actual Block variable (navigating

View File

@ -1719,6 +1719,7 @@ static void writeDISubprogram(raw_ostream &Out, const DISubprogram *N,
Printer.printMetadata("templateParams", N->getRawTemplateParams());
Printer.printMetadata("declaration", N->getRawDeclaration());
Printer.printMetadata("variables", N->getRawVariables());
Printer.printMetadata("thrownTypes", N->getRawThrownTypes());
Out << ")";
}

View File

@ -676,13 +676,14 @@ DISubprogram *DIBuilder::createFunction(
DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *File,
unsigned LineNo, DISubroutineType *Ty, bool isLocalToUnit,
bool isDefinition, unsigned ScopeLine, DINode::DIFlags Flags,
bool isOptimized, DITemplateParameterArray TParams, DISubprogram *Decl) {
bool isOptimized, DITemplateParameterArray TParams, DISubprogram *Decl,
DITypeArray ThrownTypes) {
auto *Node = getSubprogram(
/* IsDistinct = */ isDefinition, VMContext,
getNonCompileUnitScope(Context), Name, LinkageName, File, LineNo, Ty,
isLocalToUnit, isDefinition, ScopeLine, nullptr, 0, 0, 0, Flags,
isOptimized, isDefinition ? CUNode : nullptr, TParams, Decl,
MDTuple::getTemporary(VMContext, None).release());
MDTuple::getTemporary(VMContext, None).release(), ThrownTypes);
if (isDefinition)
AllSubprograms.push_back(Node);
@ -694,23 +695,22 @@ DISubprogram *DIBuilder::createTempFunctionFwdDecl(
DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *File,
unsigned LineNo, DISubroutineType *Ty, bool isLocalToUnit,
bool isDefinition, unsigned ScopeLine, DINode::DIFlags Flags,
bool isOptimized, DITemplateParameterArray TParams, DISubprogram *Decl) {
bool isOptimized, DITemplateParameterArray TParams, DISubprogram *Decl,
DITypeArray ThrownTypes) {
return DISubprogram::getTemporary(
VMContext, getNonCompileUnitScope(Context), Name, LinkageName,
File, LineNo, Ty, isLocalToUnit, isDefinition, ScopeLine, nullptr,
0, 0, 0, Flags, isOptimized, isDefinition ? CUNode : nullptr,
TParams, Decl, nullptr)
TParams, Decl, nullptr, ThrownTypes)
.release();
}
DISubprogram *DIBuilder::createMethod(DIScope *Context, StringRef Name,
StringRef LinkageName, DIFile *F,
unsigned LineNo, DISubroutineType *Ty,
bool isLocalToUnit, bool isDefinition,
unsigned VK, unsigned VIndex,
int ThisAdjustment, DIType *VTableHolder,
DINode::DIFlags Flags, bool isOptimized,
DITemplateParameterArray TParams) {
DISubprogram *DIBuilder::createMethod(
DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F,
unsigned LineNo, DISubroutineType *Ty, bool isLocalToUnit,
bool isDefinition, unsigned VK, unsigned VIndex, int ThisAdjustment,
DIType *VTableHolder, DINode::DIFlags Flags, bool isOptimized,
DITemplateParameterArray TParams, DITypeArray ThrownTypes) {
assert(getNonCompileUnitScope(Context) &&
"Methods should have both a Context and a context that isn't "
"the compile unit.");
@ -719,7 +719,7 @@ DISubprogram *DIBuilder::createMethod(DIScope *Context, StringRef Name,
/* IsDistinct = */ isDefinition, VMContext, cast<DIScope>(Context), Name,
LinkageName, F, LineNo, Ty, isLocalToUnit, isDefinition, LineNo,
VTableHolder, VK, VIndex, ThisAdjustment, Flags, isOptimized,
isDefinition ? CUNode : nullptr, TParams, nullptr, nullptr);
isDefinition ? CUNode : nullptr, TParams, nullptr, nullptr, ThrownTypes);
if (isDefinition)
AllSubprograms.push_back(SP);

View File

@ -441,17 +441,17 @@ DISubprogram *DISubprogram::getImpl(
Metadata *ContainingType, unsigned Virtuality, unsigned VirtualIndex,
int ThisAdjustment, DIFlags Flags, bool IsOptimized, Metadata *Unit,
Metadata *TemplateParams, Metadata *Declaration, Metadata *Variables,
StorageType Storage, bool ShouldCreate) {
Metadata *ThrownTypes, StorageType Storage, bool ShouldCreate) {
assert(isCanonical(Name) && "Expected canonical MDString");
assert(isCanonical(LinkageName) && "Expected canonical MDString");
DEFINE_GETIMPL_LOOKUP(
DISubprogram,
(Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition,
ScopeLine, ContainingType, Virtuality, VirtualIndex, ThisAdjustment,
Flags, IsOptimized, Unit, TemplateParams, Declaration, Variables));
DISubprogram, (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit,
IsDefinition, ScopeLine, ContainingType, Virtuality,
VirtualIndex, ThisAdjustment, Flags, IsOptimized, Unit,
TemplateParams, Declaration, Variables, ThrownTypes));
Metadata *Ops[] = {File, Scope, Name, Name,
LinkageName, Type, ContainingType, Unit,
TemplateParams, Declaration, Variables};
TemplateParams, Declaration, Variables, ThrownTypes};
DEFINE_GETIMPL_STORE(DISubprogram, (Line, ScopeLine, Virtuality, VirtualIndex,
ThisAdjustment, Flags, IsLocalToUnit,
IsDefinition, IsOptimized),

View File

@ -552,6 +552,7 @@ template <> struct MDNodeKeyImpl<DISubprogram> {
Metadata *TemplateParams;
Metadata *Declaration;
Metadata *Variables;
Metadata *ThrownTypes;
MDNodeKeyImpl(Metadata *Scope, MDString *Name, MDString *LinkageName,
Metadata *File, unsigned Line, Metadata *Type,
@ -559,7 +560,8 @@ template <> struct MDNodeKeyImpl<DISubprogram> {
Metadata *ContainingType, unsigned Virtuality,
unsigned VirtualIndex, int ThisAdjustment, unsigned Flags,
bool IsOptimized, Metadata *Unit, Metadata *TemplateParams,
Metadata *Declaration, Metadata *Variables)
Metadata *Declaration, Metadata *Variables,
Metadata *ThrownTypes)
: Scope(Scope), Name(Name), LinkageName(LinkageName), File(File),
Line(Line), Type(Type), IsLocalToUnit(IsLocalToUnit),
IsDefinition(IsDefinition), ScopeLine(ScopeLine),
@ -567,7 +569,7 @@ template <> struct MDNodeKeyImpl<DISubprogram> {
VirtualIndex(VirtualIndex), ThisAdjustment(ThisAdjustment),
Flags(Flags), IsOptimized(IsOptimized), Unit(Unit),
TemplateParams(TemplateParams), Declaration(Declaration),
Variables(Variables) {}
Variables(Variables), ThrownTypes(ThrownTypes) {}
MDNodeKeyImpl(const DISubprogram *N)
: Scope(N->getRawScope()), Name(N->getRawName()),
LinkageName(N->getRawLinkageName()), File(N->getRawFile()),
@ -578,7 +580,8 @@ template <> struct MDNodeKeyImpl<DISubprogram> {
ThisAdjustment(N->getThisAdjustment()), Flags(N->getFlags()),
IsOptimized(N->isOptimized()), Unit(N->getRawUnit()),
TemplateParams(N->getRawTemplateParams()),
Declaration(N->getRawDeclaration()), Variables(N->getRawVariables()) {}
Declaration(N->getRawDeclaration()), Variables(N->getRawVariables()),
ThrownTypes(N->getRawThrownTypes()) {}
bool isKeyOf(const DISubprogram *RHS) const {
return Scope == RHS->getRawScope() && Name == RHS->getRawName() &&
@ -595,7 +598,8 @@ template <> struct MDNodeKeyImpl<DISubprogram> {
Unit == RHS->getUnit() &&
TemplateParams == RHS->getRawTemplateParams() &&
Declaration == RHS->getRawDeclaration() &&
Variables == RHS->getRawVariables();
Variables == RHS->getRawVariables() &&
ThrownTypes == RHS->getRawThrownTypes();
}
unsigned getHashValue() const {
// If this is a declaration inside an ODR type, only hash the type and the

View File

@ -1050,6 +1050,14 @@ void Verifier::visitDISubprogram(const DISubprogram &N) {
// Subprogram declarations (part of the type hierarchy).
AssertDI(!Unit, "subprogram declarations must not have a compile unit", &N);
}
if (auto *RawThrownTypes = N.getRawThrownTypes()) {
auto *ThrownTypes = dyn_cast<MDTuple>(RawThrownTypes);
AssertDI(ThrownTypes, "invalid thrown types list", &N, RawThrownTypes);
for (Metadata *Op : ThrownTypes->operands())
AssertDI(Op && isa<DIType>(Op), "invalid thrown type", &N, ThrownTypes,
Op);
}
}
void Verifier::visitDILexicalBlockBase(const DILexicalBlockBase &N) {

View File

@ -6,8 +6,8 @@ define void @_Z3foov() !dbg !9 {
ret void
}
; CHECK: !named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12}
!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12}
; CHECK: !named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13, !14}
!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13, !14}
!0 = !{null}
!1 = distinct !DICompositeType(tag: DW_TAG_structure_type)
@ -61,6 +61,14 @@ define void @_Z3foov() !dbg !9 {
unit: !8,
templateParams: !5, declaration: !9, variables: !6)
!13 = !{i32 1, !"Debug Info Version", i32 3}
!llvm.module.flags = !{!13}
!13 = !{!4}
; CHECK: !13 = !{!4}
; CHECK: !14 = distinct !DISubprogram(name: "foo", scope: !1, file: !2, line: 1, type: !3, isLocal: true, isDefinition: true, scopeLine: 2, isOptimized: false, unit: !8, thrownTypes: !13)
!14 = distinct !DISubprogram(name: "foo", scope: !1,
file: !2, line: 1, type: !3, isLocal: true,
isDefinition: true, scopeLine: 2, isOptimized: false,
unit: !8, thrownTypes: !13)
!15 = !{i32 1, !"Debug Info Version", i32 3}
!llvm.module.flags = !{!15}
!llvm.dbg.cu = !{!8}

View File

@ -0,0 +1,38 @@
; REQUIRES: object-emission
; RUN: %llc_dwarf -O0 -filetype=obj < %s | llvm-dwarfdump -debug-dump=info - | FileCheck %s
; CHECK: DW_TAG_subprogram
; CHECK: DW_AT_name {{.*}} "f"
; CHECK-NOT: DW_TAG
; CHECK: DW_TAG_thrown_type
; CHECK-NEXT: DW_AT_type {{.*}} {[[ERROR:.*]]}
; CHECK-NOT: DW_TAG
; CHECK: DW_TAG_thrown_type
; CHECK-NEXT: DW_AT_type {{.*}} {[[ERROR2:.*]]}
; CHECK: [[ERROR]]: DW_TAG_structure_type
; CHECK-NEXT: DW_AT_name {{.*}} "Error"
; CHECK: [[ERROR2]]: DW_TAG_structure_type
; CHECK-NEXT: DW_AT_name {{.*}} "DifferentError"
; Function Attrs: nounwind uwtable
define void @f() #0 !dbg !5 {
entry:
ret void, !dbg !11
}
attributes #0 = { nounwind uwtable }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!8, !9}
!0 = distinct !DICompileUnit(language: DW_LANG_Swift, producer: "swiftc", isOptimized: false, emissionKind: FullDebug, file: !1)
!1 = !DIFile(filename: "f.swift", directory: "/")
!3 = !DICompositeType(tag: DW_TAG_structure_type, name: "Error")
!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "DifferentError")
!5 = distinct !DISubprogram(name: "f", line: 2, isLocal: false, isDefinition: true, unit: !0, scopeLine: 2, file: !1, scope: !1, type: !6, thrownTypes: !{!3, !4})
!6 = !DISubroutineType(types: !7)
!7 = !{null}
!8 = !{i32 2, !"Dwarf Version", i32 4}
!9 = !{i32 1, !"Debug Info Version", i32 3}
!11 = !DILocation(line: 3, scope: !5)

View File

@ -0,0 +1,22 @@
; RUN: not opt -S <%s 2>&1| FileCheck %s
define void @f() !dbg !14 {
ret void
}
!0 = !{null}
!1 = distinct !DICompositeType(tag: DW_TAG_structure_type)
!2 = !DIFile(filename: "path/to/file", directory: "/path/to/dir")
!3 = !DISubroutineType(types: !0)
!4 = distinct !DICompositeType(tag: DW_TAG_structure_type)
!8 = distinct !DICompileUnit(language: DW_LANG_Swift, producer: "clang",
file: !2, emissionKind: 2)
; CHECK: invalid thrown type
!13 = !{!14}
!14 = distinct !DISubprogram(name: "f", scope: !1,
file: !2, line: 1, type: !3, isLocal: true,
isDefinition: true, scopeLine: 2,
unit: !8, thrownTypes: !13)
!15 = !{i32 1, !"Debug Info Version", i32 3}
!llvm.module.flags = !{!15}
!llvm.dbg.cu = !{!8}

View File

@ -356,6 +356,25 @@ TEST_F(IRBuilderTest, RAIIHelpersTest) {
EXPECT_EQ(BB, Builder.GetInsertBlock());
}
TEST_F(IRBuilderTest, createFunction) {
IRBuilder<> Builder(BB);
DIBuilder DIB(*M);
auto File = DIB.createFile("error.swift", "/");
auto CU =
DIB.createCompileUnit(dwarf::DW_LANG_Swift, File, "swiftc", true, "", 0);
auto Type = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
auto NoErr = DIB.createFunction(CU, "noerr", "", File, 1, Type, false, true, 1,
DINode::FlagZero, true);
EXPECT_TRUE(!NoErr->getThrownTypes());
auto Int = DIB.createBasicType("Int", 64, dwarf::DW_ATE_signed);
auto Error = DIB.getOrCreateArray({Int});
auto Err =
DIB.createFunction(CU, "err", "", File, 1, Type, false, true, 1,
DINode::FlagZero, true, nullptr, nullptr, Error.get());
EXPECT_TRUE(Err->getThrownTypes().get() == Error.get());
DIB.finalize();
}
TEST_F(IRBuilderTest, DIBuilder) {
IRBuilder<> Builder(BB);
DIBuilder DIB(*M);

View File

@ -1512,13 +1512,14 @@ TEST_F(DISubprogramTest, get) {
MDTuple *TemplateParams = getTuple();
DISubprogram *Declaration = getSubprogram();
MDTuple *Variables = getTuple();
MDTuple *ThrownTypes = getTuple();
DICompileUnit *Unit = getUnit();
auto *N = DISubprogram::get(Context, Scope, Name, LinkageName, File, Line,
Type, IsLocalToUnit, IsDefinition, ScopeLine,
ContainingType, Virtuality, VirtualIndex,
ThisAdjustment, Flags, IsOptimized, Unit,
TemplateParams, Declaration, Variables);
auto *N = DISubprogram::get(
Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit,
IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex,
ThisAdjustment, Flags, IsOptimized, Unit, TemplateParams, Declaration,
Variables, ThrownTypes);
EXPECT_EQ(dwarf::DW_TAG_subprogram, N->getTag());
EXPECT_EQ(Scope, N->getScope());
@ -1540,98 +1541,109 @@ TEST_F(DISubprogramTest, get) {
EXPECT_EQ(TemplateParams, N->getTemplateParams().get());
EXPECT_EQ(Declaration, N->getDeclaration());
EXPECT_EQ(Variables, N->getVariables().get());
EXPECT_EQ(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line,
Type, IsLocalToUnit, IsDefinition, ScopeLine,
ContainingType, Virtuality, VirtualIndex,
ThisAdjustment, Flags, IsOptimized, Unit,
TemplateParams, Declaration, Variables));
EXPECT_EQ(ThrownTypes, N->getThrownTypes().get());
EXPECT_EQ(N, DISubprogram::get(
Context, Scope, Name, LinkageName, File, Line, Type,
IsLocalToUnit, IsDefinition, ScopeLine, ContainingType,
Virtuality, VirtualIndex, ThisAdjustment, Flags, IsOptimized,
Unit, TemplateParams, Declaration, Variables, ThrownTypes));
EXPECT_NE(N, DISubprogram::get(
Context, getCompositeType(), Name, LinkageName, File, Line,
Type, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType,
Virtuality, VirtualIndex, ThisAdjustment, Flags, IsOptimized,
Unit, TemplateParams, Declaration, Variables));
Unit, TemplateParams, Declaration, Variables, ThrownTypes));
EXPECT_NE(N, DISubprogram::get(
Context, Scope, "other", LinkageName, File, Line, Type,
IsLocalToUnit, IsDefinition, ScopeLine, ContainingType,
Virtuality, VirtualIndex, ThisAdjustment, Flags, IsOptimized,
Unit, TemplateParams, Declaration, Variables));
EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, "other", File, Line,
Type, IsLocalToUnit, IsDefinition, ScopeLine,
ContainingType, Virtuality, VirtualIndex,
ThisAdjustment, Flags, IsOptimized, Unit,
TemplateParams, Declaration, Variables));
Unit, TemplateParams, Declaration, Variables, ThrownTypes));
EXPECT_NE(N, DISubprogram::get(
Context, Scope, Name, "other", File, Line, Type,
IsLocalToUnit, IsDefinition, ScopeLine, ContainingType,
Virtuality, VirtualIndex, ThisAdjustment, Flags, IsOptimized,
Unit, TemplateParams, Declaration, Variables, ThrownTypes));
EXPECT_NE(N, DISubprogram::get(
Context, Scope, Name, LinkageName, getFile(), Line, Type,
IsLocalToUnit, IsDefinition, ScopeLine, ContainingType,
Virtuality, VirtualIndex, ThisAdjustment, Flags, IsOptimized,
Unit, TemplateParams, Declaration, Variables));
Unit, TemplateParams, Declaration, Variables, ThrownTypes));
EXPECT_NE(N, DISubprogram::get(
Context, Scope, Name, LinkageName, File, Line + 1, Type,
IsLocalToUnit, IsDefinition, ScopeLine, ContainingType,
Virtuality, VirtualIndex, ThisAdjustment, Flags, IsOptimized,
Unit, TemplateParams, Declaration, Variables));
EXPECT_NE(N,
DISubprogram::get(Context, Scope, Name, LinkageName, File, Line,
getSubroutineType(), IsLocalToUnit, IsDefinition,
ScopeLine, ContainingType, Virtuality,
VirtualIndex, ThisAdjustment, Flags, IsOptimized,
Unit, TemplateParams, Declaration, Variables));
Unit, TemplateParams, Declaration, Variables, ThrownTypes));
EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line,
Type, !IsLocalToUnit, IsDefinition, ScopeLine,
ContainingType, Virtuality, VirtualIndex,
ThisAdjustment, Flags, IsOptimized, Unit,
TemplateParams, Declaration, Variables));
EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line,
Type, IsLocalToUnit, !IsDefinition, ScopeLine,
ContainingType, Virtuality, VirtualIndex,
ThisAdjustment, Flags, IsOptimized, Unit,
TemplateParams, Declaration, Variables));
getSubroutineType(), IsLocalToUnit,
IsDefinition, ScopeLine, ContainingType,
Virtuality, VirtualIndex, ThisAdjustment,
Flags, IsOptimized, Unit, TemplateParams,
Declaration, Variables, ThrownTypes));
EXPECT_NE(N, DISubprogram::get(
Context, Scope, Name, LinkageName, File, Line, Type,
!IsLocalToUnit, IsDefinition, ScopeLine, ContainingType,
Virtuality, VirtualIndex, ThisAdjustment, Flags, IsOptimized,
Unit, TemplateParams, Declaration, Variables, ThrownTypes));
EXPECT_NE(N, DISubprogram::get(
Context, Scope, Name, LinkageName, File, Line, Type,
IsLocalToUnit, !IsDefinition, ScopeLine, ContainingType,
Virtuality, VirtualIndex, ThisAdjustment, Flags, IsOptimized,
Unit, TemplateParams, Declaration, Variables, ThrownTypes));
EXPECT_NE(N, DISubprogram::get(
Context, Scope, Name, LinkageName, File, Line, Type,
IsLocalToUnit, IsDefinition, ScopeLine + 1, ContainingType,
Virtuality, VirtualIndex, ThisAdjustment, Flags, IsOptimized,
Unit, TemplateParams, Declaration, Variables));
EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line,
Type, IsLocalToUnit, IsDefinition, ScopeLine,
getCompositeType(), Virtuality, VirtualIndex,
ThisAdjustment, Flags, IsOptimized, Unit,
TemplateParams, Declaration, Variables));
Unit, TemplateParams, Declaration, Variables, ThrownTypes));
EXPECT_NE(N, DISubprogram::get(
Context, Scope, Name, LinkageName, File, Line, Type,
IsLocalToUnit, IsDefinition, ScopeLine, getCompositeType(),
Virtuality, VirtualIndex, ThisAdjustment, Flags, IsOptimized,
Unit, TemplateParams, Declaration, Variables, ThrownTypes));
EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line,
Type, IsLocalToUnit, IsDefinition, ScopeLine,
ContainingType, Virtuality + 1, VirtualIndex,
ThisAdjustment, Flags, IsOptimized, Unit,
TemplateParams, Declaration, Variables));
TemplateParams, Declaration, Variables,
ThrownTypes));
EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line,
Type, IsLocalToUnit, IsDefinition, ScopeLine,
ContainingType, Virtuality, VirtualIndex + 1,
ThisAdjustment, Flags, IsOptimized, Unit,
TemplateParams, Declaration, Variables));
TemplateParams, Declaration, Variables,
ThrownTypes));
EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line,
Type, IsLocalToUnit, IsDefinition, ScopeLine,
ContainingType, Virtuality, VirtualIndex,
ThisAdjustment, Flags, !IsOptimized, Unit,
TemplateParams, Declaration, Variables));
TemplateParams, Declaration, Variables,
ThrownTypes));
EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line,
Type, IsLocalToUnit, IsDefinition, ScopeLine,
ContainingType, Virtuality, VirtualIndex,
ThisAdjustment, Flags, IsOptimized, nullptr,
TemplateParams, Declaration, Variables));
TemplateParams, Declaration, Variables,
ThrownTypes));
EXPECT_NE(N, DISubprogram::get(
Context, Scope, Name, LinkageName, File, Line, Type,
IsLocalToUnit, IsDefinition, ScopeLine, ContainingType,
Virtuality, VirtualIndex, ThisAdjustment, Flags, IsOptimized,
Unit, getTuple(), Declaration, Variables, ThrownTypes));
EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line,
Type, IsLocalToUnit, IsDefinition, ScopeLine,
ContainingType, Virtuality, VirtualIndex,
ThisAdjustment, Flags, IsOptimized, Unit,
getTuple(), Declaration, Variables));
EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line,
Type, IsLocalToUnit, IsDefinition, ScopeLine,
ContainingType, Virtuality, VirtualIndex,
ThisAdjustment, Flags, IsOptimized, Unit,
TemplateParams, getSubprogram(), Variables));
TemplateParams, getSubprogram(), Variables,
ThrownTypes));
EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line,
Type, IsLocalToUnit, IsDefinition, ScopeLine,
ContainingType, Virtuality, VirtualIndex,
ThisAdjustment, Flags, IsOptimized, Unit,
TemplateParams, Declaration, getTuple()));
EXPECT_NE(N, DISubprogram::get(
Context, Scope, Name, LinkageName, File, Line, Type,
IsLocalToUnit, IsDefinition, ScopeLine, ContainingType,
Virtuality, VirtualIndex, ThisAdjustment, Flags, IsOptimized,
Unit, TemplateParams, Declaration, Variables, getTuple()));
TempDISubprogram Temp = N->clone();
EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp)));