From 1d12b885b09a92d268356292c2829a2a6b4aca1d Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Wed, 26 Apr 2017 22:56:44 +0000 Subject: [PATCH] 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 --- llvm/include/llvm/IR/DIBuilder.h | 23 +++--- llvm/include/llvm/IR/DebugInfoMetadata.h | 40 ++++++----- llvm/lib/AsmParser/LLParser.cpp | 17 ++--- llvm/lib/Bitcode/Reader/MetadataLoader.cpp | 48 +++++++------ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 1 + llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp | 10 +++ llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h | 3 + llvm/lib/IR/AsmWriter.cpp | 1 + llvm/lib/IR/DIBuilder.cpp | 26 +++---- llvm/lib/IR/DebugInfoMetadata.cpp | 12 ++-- llvm/lib/IR/LLVMContextImpl.h | 12 ++-- llvm/lib/IR/Verifier.cpp | 8 +++ llvm/test/Assembler/disubprogram.ll | 16 +++-- llvm/test/DebugInfo/Generic/thrownTypes.ll | 38 ++++++++++ llvm/test/Verifier/DISubprogram.ll | 22 ++++++ llvm/unittests/IR/IRBuilderTest.cpp | 19 +++++ llvm/unittests/IR/MetadataTest.cpp | 112 ++++++++++++++++------------- 17 files changed, 272 insertions(+), 136 deletions(-) create mode 100644 llvm/test/DebugInfo/Generic/thrownTypes.ll create mode 100644 llvm/test/Verifier/DISubprogram.ll diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h index a4b2a02..0656878 100644 --- a/llvm/include/llvm/IR/DIBuilder.h +++ b/llvm/include/llvm/IR/DIBuilder.h @@ -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. diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index 8041e35..ae11181 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -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(getRawUnit()); } - void replaceUnit(DICompileUnit *CU) { - replaceOperandWith(7, CU); - } + void replaceUnit(DICompileUnit *CU) { replaceOperandWith(7, CU); } DITemplateParameterArray getTemplateParams() const { return cast_or_null(getRawTemplateParams()); } @@ -1638,6 +1640,9 @@ public: DILocalVariableArray getVariables() const { return cast_or_null(getRawVariables()); } + DITypeArray getThrownTypes() const { + return cast_or_null(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. /// diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index c7076ed..a6a9b32 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -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; } diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp index d089684..7ca2e16 100644 --- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -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(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(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++; diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index e5aba03..eb8b432 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -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(); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index 16fb20d..f2e1399 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -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(Ty)); + } +} + DIE *DwarfUnit::getOrCreateContextDIE(const DIScope *Context) { if (!Context || isa(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); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h index e84df46..3bf4979 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -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 diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index b7de071..e396716 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -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 << ")"; } diff --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp index 9407c80..24f75e8 100644 --- a/llvm/lib/IR/DIBuilder.cpp +++ b/llvm/lib/IR/DIBuilder.cpp @@ -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(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); diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index d14c601..498617c 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -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), diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h index 0ee0b9c..d2c4b02 100644 --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -552,6 +552,7 @@ template <> struct MDNodeKeyImpl { 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 { 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 { 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 { 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 { 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 diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 4e04020..5f60774 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -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(RawThrownTypes); + AssertDI(ThrownTypes, "invalid thrown types list", &N, RawThrownTypes); + for (Metadata *Op : ThrownTypes->operands()) + AssertDI(Op && isa(Op), "invalid thrown type", &N, ThrownTypes, + Op); + } } void Verifier::visitDILexicalBlockBase(const DILexicalBlockBase &N) { diff --git a/llvm/test/Assembler/disubprogram.ll b/llvm/test/Assembler/disubprogram.ll index f6352a5..8a3a60a 100644 --- a/llvm/test/Assembler/disubprogram.ll +++ b/llvm/test/Assembler/disubprogram.ll @@ -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} diff --git a/llvm/test/DebugInfo/Generic/thrownTypes.ll b/llvm/test/DebugInfo/Generic/thrownTypes.ll new file mode 100644 index 0000000..8e84e7b --- /dev/null +++ b/llvm/test/DebugInfo/Generic/thrownTypes.ll @@ -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) diff --git a/llvm/test/Verifier/DISubprogram.ll b/llvm/test/Verifier/DISubprogram.ll new file mode 100644 index 0000000..e78220c --- /dev/null +++ b/llvm/test/Verifier/DISubprogram.ll @@ -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} diff --git a/llvm/unittests/IR/IRBuilderTest.cpp b/llvm/unittests/IR/IRBuilderTest.cpp index 830ae95..5686c3b 100644 --- a/llvm/unittests/IR/IRBuilderTest.cpp +++ b/llvm/unittests/IR/IRBuilderTest.cpp @@ -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); diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp index 103ba4c..8dc9795 100644 --- a/llvm/unittests/IR/MetadataTest.cpp +++ b/llvm/unittests/IR/MetadataTest.cpp @@ -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)); - 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)); + 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)); + 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)); - 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)); + 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, - 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))); -- 2.7.4