From 9a09a465e5b9eecaf0caf8109ed7816e567f8d96 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Tue, 6 Feb 2018 23:45:59 +0000 Subject: [PATCH] Add DWARF for discriminated unions n Rust, an enum that carries data in the variants is, essentially, a discriminated union. Furthermore, the Rust compiler will perform space optimizations on such enums in some situations. Previously, DWARF for these constructs was emitted using a hack (a magic field name); but this approach stopped working when more space optimizations were added in https://github.com/rust-lang/rust/pull/45225. This patch changes LLVM to allow discriminated unions to be represented in DWARF. It adds createDiscriminatedUnionType and createDiscriminatedMemberType to DIBuilder and then arranges for this to be emitted using DWARF's DW_TAG_variant_part and DW_TAG_variant. Note that DWARF requires that a discriminated union be represented as a structure with a variant part. However, as Rust only needs to emit pure discriminated unions, this is what I chose to expose on DIBuilder. Patch by Tom Tromey! Differential Revision: https://reviews.llvm.org/D42082 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@324426 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/DIBuilder.h | 42 ++++++++++ include/llvm/IR/DebugInfoMetadata.h | 31 ++++--- lib/AsmParser/LLParser.cpp | 8 +- lib/BinaryFormat/Dwarf.cpp | 12 --- lib/Bitcode/Reader/MetadataLoader.cpp | 7 +- lib/Bitcode/Writer/BitcodeWriter.cpp | 1 + lib/CodeGen/AsmPrinter/DwarfUnit.cpp | 36 ++++++++- lib/CodeGen/AsmPrinter/DwarfUnit.h | 2 +- lib/IR/AsmWriter.cpp | 1 + lib/IR/DIBuilder.cpp | 25 ++++++ lib/IR/DebugInfoMetadata.cpp | 20 ++--- lib/IR/LLVMContextImpl.h | 12 ++- lib/IR/Verifier.cpp | 8 +- test/Assembler/debug-info.ll | 11 ++- test/DebugInfo/Generic/discriminated-union.ll | 80 +++++++++++++++++++ .../Generic/univariant-discriminated-union.ll | 65 +++++++++++++++ test/Verifier/variant-part.ll | 8 ++ unittests/IR/DebugTypeODRUniquingTest.cpp | 22 ++--- unittests/IR/MetadataTest.cpp | 45 +++++++++++ 19 files changed, 380 insertions(+), 56 deletions(-) create mode 100644 test/DebugInfo/Generic/discriminated-union.ll create mode 100644 test/DebugInfo/Generic/univariant-discriminated-union.ll create mode 100644 test/Verifier/variant-part.ll diff --git a/include/llvm/IR/DIBuilder.h b/include/llvm/IR/DIBuilder.h index 3c2074dfe788..a538ac1913ff 100644 --- a/include/llvm/IR/DIBuilder.h +++ b/include/llvm/IR/DIBuilder.h @@ -255,6 +255,27 @@ namespace llvm { uint64_t OffsetInBits, DINode::DIFlags Flags, DIType *Ty); + /// Create debugging information entry for a variant. A variant + /// normally should be a member of a variant part. + /// \param Scope Member scope. + /// \param Name Member name. + /// \param File File where this member is defined. + /// \param LineNo Line number. + /// \param SizeInBits Member size. + /// \param AlignInBits Member alignment. + /// \param OffsetInBits Member offset. + /// \param Flags Flags to encode member attribute, e.g. private + /// \param Discriminant The discriminant for this branch; null for + /// the default branch + /// \param Ty Parent type. + DIDerivedType *createVariantMemberType(DIScope *Scope, StringRef Name, + DIFile *File, unsigned LineNo, + uint64_t SizeInBits, + uint32_t AlignInBits, + uint64_t OffsetInBits, + Constant *Discriminant, + DINode::DIFlags Flags, DIType *Ty); + /// Create debugging information entry for a bit field member. /// \param Scope Member scope. /// \param Name Member name. @@ -376,6 +397,27 @@ namespace llvm { unsigned RunTimeLang = 0, StringRef UniqueIdentifier = ""); + /// Create debugging information entry for a variant part. A + /// variant part normally has a discriminator (though this is not + /// required) and a number of variant children. + /// \param Scope Scope in which this union is defined. + /// \param Name Union name. + /// \param File File where this member is defined. + /// \param LineNumber Line number. + /// \param SizeInBits Member size. + /// \param AlignInBits Member alignment. + /// \param Flags Flags to encode member attribute, e.g. private + /// \param Discriminator Discriminant member + /// \param Elements Variant elements. + /// \param UniqueIdentifier A unique identifier for the union. + DICompositeType *createVariantPart(DIScope *Scope, StringRef Name, + DIFile *File, unsigned LineNumber, + uint64_t SizeInBits, uint32_t AlignInBits, + DINode::DIFlags Flags, + DIDerivedType *Discriminator, + DINodeArray Elements, + StringRef UniqueIdentifier = ""); + /// Create debugging information for template /// type parameter. /// \param Scope Scope in which this type is defined. diff --git a/include/llvm/IR/DebugInfoMetadata.h b/include/llvm/IR/DebugInfoMetadata.h index 75b0c43b6512..d7284ae8c5d4 100644 --- a/include/llvm/IR/DebugInfoMetadata.h +++ b/include/llvm/IR/DebugInfoMetadata.h @@ -819,6 +819,12 @@ class DIDerivedType : public DIType { return C->getValue(); return nullptr; } + Constant *getDiscriminantValue() const { + assert(getTag() == dwarf::DW_TAG_member && !isStaticMember()); + if (auto *C = cast_or_null(getExtraData())) + return C->getValue(); + return nullptr; + } /// @} static bool classof(const Metadata *MD) { @@ -861,12 +867,13 @@ class DICompositeType : public DIType { uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, DIFlags Flags, DINodeArray Elements, unsigned RuntimeLang, DITypeRef VTableHolder, DITemplateParameterArray TemplateParams, - StringRef Identifier, StorageType Storage, bool ShouldCreate = true) { + StringRef Identifier, DIDerivedType *Discriminator, + StorageType Storage, bool ShouldCreate = true) { return getImpl( Context, Tag, getCanonicalMDString(Context, Name), File, Line, Scope, BaseType, SizeInBits, AlignInBits, OffsetInBits, Flags, Elements.get(), RuntimeLang, VTableHolder, TemplateParams.get(), - getCanonicalMDString(Context, Identifier), Storage, ShouldCreate); + getCanonicalMDString(Context, Identifier), Discriminator, Storage, ShouldCreate); } static DICompositeType * getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *File, @@ -874,14 +881,15 @@ class DICompositeType : public DIType { uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, DIFlags Flags, Metadata *Elements, unsigned RuntimeLang, Metadata *VTableHolder, Metadata *TemplateParams, - MDString *Identifier, StorageType Storage, bool ShouldCreate = true); + MDString *Identifier, Metadata *Discriminator, + StorageType Storage, bool ShouldCreate = true); TempDICompositeType cloneImpl() const { return getTemporary(getContext(), getTag(), getName(), getFile(), getLine(), getScope(), getBaseType(), getSizeInBits(), getAlignInBits(), getOffsetInBits(), getFlags(), getElements(), getRuntimeLang(), getVTableHolder(), - getTemplateParams(), getIdentifier()); + getTemplateParams(), getIdentifier(), getDiscriminator()); } public: @@ -892,10 +900,10 @@ class DICompositeType : public DIType { DIFlags Flags, DINodeArray Elements, unsigned RuntimeLang, DITypeRef VTableHolder, DITemplateParameterArray TemplateParams = nullptr, - StringRef Identifier = ""), + StringRef Identifier = "", DIDerivedType *Discriminator = nullptr), (Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang, - VTableHolder, TemplateParams, Identifier)) + VTableHolder, TemplateParams, Identifier, Discriminator)) DEFINE_MDNODE_GET(DICompositeType, (unsigned Tag, MDString *Name, Metadata *File, unsigned Line, Metadata *Scope, Metadata *BaseType, @@ -903,10 +911,11 @@ class DICompositeType : public DIType { uint64_t OffsetInBits, DIFlags Flags, Metadata *Elements, unsigned RuntimeLang, Metadata *VTableHolder, Metadata *TemplateParams = nullptr, - MDString *Identifier = nullptr), + MDString *Identifier = nullptr, + Metadata *Discriminator = nullptr), (Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang, - VTableHolder, TemplateParams, Identifier)) + VTableHolder, TemplateParams, Identifier, Discriminator)) TempDICompositeType clone() const { return cloneImpl(); } @@ -923,7 +932,7 @@ class DICompositeType : public DIType { Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, DIFlags Flags, Metadata *Elements, unsigned RuntimeLang, Metadata *VTableHolder, - Metadata *TemplateParams); + Metadata *TemplateParams, Metadata *Discriminator); static DICompositeType *getODRTypeIfExists(LLVMContext &Context, MDString &Identifier); @@ -942,7 +951,7 @@ class DICompositeType : public DIType { Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, DIFlags Flags, Metadata *Elements, unsigned RuntimeLang, Metadata *VTableHolder, - Metadata *TemplateParams); + Metadata *TemplateParams, Metadata *Discriminator); DITypeRef getBaseType() const { return DITypeRef(getRawBaseType()); } DINodeArray getElements() const { @@ -960,6 +969,8 @@ class DICompositeType : public DIType { Metadata *getRawVTableHolder() const { return getOperand(5); } Metadata *getRawTemplateParams() const { return getOperand(6); } MDString *getRawIdentifier() const { return getOperandAs(7); } + Metadata *getRawDiscriminator() const { return getOperand(8); } + DIDerivedType *getDiscriminator() const { return getOperandAs(8); } /// Replace operands. /// diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index c3ab95550e03..fc4071a4a809 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -4068,7 +4068,8 @@ bool LLParser::ParseDICompositeType(MDNode *&Result, bool IsDistinct) { OPTIONAL(runtimeLang, DwarfLangField, ); \ OPTIONAL(vtableHolder, MDField, ); \ OPTIONAL(templateParams, MDField, ); \ - OPTIONAL(identifier, MDStringField, ); + OPTIONAL(identifier, MDStringField, ); \ + OPTIONAL(discriminator, MDField, ); PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS @@ -4078,7 +4079,7 @@ bool LLParser::ParseDICompositeType(MDNode *&Result, bool IsDistinct) { Context, *identifier.Val, tag.Val, name.Val, file.Val, line.Val, scope.Val, baseType.Val, size.Val, align.Val, offset.Val, flags.Val, elements.Val, runtimeLang.Val, vtableHolder.Val, - templateParams.Val)) { + templateParams.Val, discriminator.Val)) { Result = CT; return false; } @@ -4089,7 +4090,8 @@ bool LLParser::ParseDICompositeType(MDNode *&Result, bool IsDistinct) { DICompositeType, (Context, tag.Val, name.Val, file.Val, line.Val, scope.Val, baseType.Val, size.Val, align.Val, offset.Val, flags.Val, elements.Val, - runtimeLang.Val, vtableHolder.Val, templateParams.Val, identifier.Val)); + runtimeLang.Val, vtableHolder.Val, templateParams.Val, identifier.Val, + discriminator.Val)); return false; } diff --git a/lib/BinaryFormat/Dwarf.cpp b/lib/BinaryFormat/Dwarf.cpp index 86e3b02577fd..51cc6ae5870e 100644 --- a/lib/BinaryFormat/Dwarf.cpp +++ b/lib/BinaryFormat/Dwarf.cpp @@ -393,16 +393,6 @@ StringRef llvm::dwarf::ArrayOrderString(unsigned Order) { return StringRef(); } -StringRef llvm::dwarf::DiscriminantString(unsigned Discriminant) { - switch (Discriminant) { - case DW_DSC_label: - return "DW_DSC_label"; - case DW_DSC_range: - return "DW_DSC_range"; - } - return StringRef(); -} - StringRef llvm::dwarf::LNStandardString(unsigned Standard) { switch (Standard) { default: @@ -560,8 +550,6 @@ StringRef llvm::dwarf::AttributeValueString(uint16_t Attr, unsigned Val) { return InlineCodeString(Val); case DW_AT_ordering: return ArrayOrderString(Val); - case DW_AT_discr_value: - return DiscriminantString(Val); } return StringRef(); diff --git a/lib/Bitcode/Reader/MetadataLoader.cpp b/lib/Bitcode/Reader/MetadataLoader.cpp index 1b0d80d26cf5..4f47cbcdbfd7 100644 --- a/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/lib/Bitcode/Reader/MetadataLoader.cpp @@ -1235,7 +1235,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( break; } case bitc::METADATA_COMPOSITE_TYPE: { - if (Record.size() != 16) + if (Record.size() < 16 || Record.size() > 17) return error("Invalid record"); // If we have a UUID and this is not a forward declaration, lookup the @@ -1258,6 +1258,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( unsigned RuntimeLang = Record[12]; Metadata *VTableHolder = nullptr; Metadata *TemplateParams = nullptr; + Metadata *Discriminator = nullptr; auto *Identifier = getMDString(Record[15]); // If this module is being parsed so that it can be ThinLTO imported // into another module, composite types only need to be imported @@ -1278,13 +1279,15 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( Elements = getMDOrNull(Record[11]); VTableHolder = getDITypeRefOrNull(Record[13]); TemplateParams = getMDOrNull(Record[14]); + if (Record.size() > 16) + Discriminator = getMDOrNull(Record[16]); } DICompositeType *CT = nullptr; if (Identifier) CT = DICompositeType::buildODRType( Context, *Identifier, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang, - VTableHolder, TemplateParams); + VTableHolder, TemplateParams, Discriminator); // Create a node if we didn't get a lazy ODR type. if (!CT) diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index 7bf37857eb97..02d309264830 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1521,6 +1521,7 @@ void ModuleBitcodeWriter::writeDICompositeType( Record.push_back(VE.getMetadataOrNullID(N->getVTableHolder())); Record.push_back(VE.getMetadataOrNullID(N->getTemplateParams().get())); Record.push_back(VE.getMetadataOrNullID(N->getRawIdentifier())); + Record.push_back(VE.getMetadataOrNullID(N->getDiscriminator())); Stream.EmitRecord(bitc::METADATA_COMPOSITE_TYPE, Record, Abbrev); Record.clear(); diff --git a/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index 4ea59f504bd4..962f76831e1a 100644 --- a/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -917,9 +917,24 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { case dwarf::DW_TAG_enumeration_type: constructEnumTypeDIE(Buffer, CTy); break; + case dwarf::DW_TAG_variant_part: case dwarf::DW_TAG_structure_type: case dwarf::DW_TAG_union_type: case dwarf::DW_TAG_class_type: { + // Emit the discriminator for a variant part. + DIDerivedType *Discriminator = nullptr; + if (Tag == dwarf::DW_TAG_variant_part) { + Discriminator = CTy->getDiscriminator(); + if (Discriminator) { + // DWARF says: + // If the variant part has a discriminant, the discriminant is + // represented by a separate debugging information entry which is + // a child of the variant part entry. + DIE &DiscMember = constructMemberDIE(Buffer, Discriminator); + addDIEEntry(Buffer, dwarf::DW_AT_discr, DiscMember); + } + } + // Add elements to structure type. DINodeArray Elements = CTy->getElements(); for (const auto *Element : Elements) { @@ -933,6 +948,18 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { addType(ElemDie, resolve(DDTy->getBaseType()), dwarf::DW_AT_friend); } else if (DDTy->isStaticMember()) { getOrCreateStaticMemberDIE(DDTy); + } else if (Tag == dwarf::DW_TAG_variant_part) { + // When emitting a variant part, wrap each member in + // DW_TAG_variant. + DIE &Variant = createAndAddDIE(dwarf::DW_TAG_variant, Buffer); + if (const ConstantInt *CI = + dyn_cast_or_null(DDTy->getDiscriminantValue())) { + if (isUnsignedDIType(DD, resolve(Discriminator->getBaseType()))) + addUInt(Variant, dwarf::DW_AT_discr_value, None, CI->getZExtValue()); + else + addSInt(Variant, dwarf::DW_AT_discr_value, None, CI->getSExtValue()); + } + constructMemberDIE(Variant, DDTy); } else { constructMemberDIE(Buffer, DDTy); } @@ -952,6 +979,11 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { if (unsigned PropertyAttributes = Property->getAttributes()) addUInt(ElemDie, dwarf::DW_AT_APPLE_property_attribute, None, PropertyAttributes); + } else if (auto *Composite = dyn_cast(Element)) { + if (Composite->getTag() == dwarf::DW_TAG_variant_part) { + DIE &VariantPart = createAndAddDIE(Composite->getTag(), Buffer); + constructTypeDIE(VariantPart, Composite); + } } } @@ -1385,7 +1417,7 @@ void DwarfUnit::constructContainingTypeDIEs() { } } -void DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) { +DIE &DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) { DIE &MemberDie = createAndAddDIE(DT->getTag(), Buffer); StringRef Name = DT->getName(); if (!Name.empty()) @@ -1490,6 +1522,8 @@ void DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) { if (DT->isArtificial()) addFlag(MemberDie, dwarf::DW_AT_artificial); + + return MemberDie; } DIE *DwarfUnit::getOrCreateStaticMemberDIE(const DIDerivedType *DT) { diff --git a/lib/CodeGen/AsmPrinter/DwarfUnit.h b/lib/CodeGen/AsmPrinter/DwarfUnit.h index 4cc01b3298d4..f1c11e0cbe5f 100644 --- a/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -331,7 +331,7 @@ class DwarfUnit : public DIEUnit { void constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, DIE *IndexTy); void constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy); void constructEnumTypeDIE(DIE &Buffer, const DICompositeType *CTy); - void constructMemberDIE(DIE &Buffer, const DIDerivedType *DT); + DIE &constructMemberDIE(DIE &Buffer, const DIDerivedType *DT); void constructTemplateTypeParameterDIE(DIE &Buffer, const DITemplateTypeParameter *TP); void constructTemplateValueParameterDIE(DIE &Buffer, diff --git a/lib/IR/AsmWriter.cpp b/lib/IR/AsmWriter.cpp index 0fafe82404e4..011370bc1e56 100644 --- a/lib/IR/AsmWriter.cpp +++ b/lib/IR/AsmWriter.cpp @@ -1696,6 +1696,7 @@ static void writeDICompositeType(raw_ostream &Out, const DICompositeType *N, Printer.printMetadata("vtableHolder", N->getRawVTableHolder()); Printer.printMetadata("templateParams", N->getRawTemplateParams()); Printer.printString("identifier", N->getIdentifier()); + Printer.printMetadata("discriminator", N->getRawDiscriminator()); Out << ")"; } diff --git a/lib/IR/DIBuilder.cpp b/lib/IR/DIBuilder.cpp index a00c595d01c5..da9204bab889 100644 --- a/lib/IR/DIBuilder.cpp +++ b/lib/IR/DIBuilder.cpp @@ -333,6 +333,19 @@ static ConstantAsMetadata *getConstantOrNull(Constant *C) { return nullptr; } +DIDerivedType *DIBuilder::createVariantMemberType(DIScope *Scope, StringRef Name, + DIFile *File, unsigned LineNumber, + uint64_t SizeInBits, + uint32_t AlignInBits, + uint64_t OffsetInBits, + Constant *Discriminant, + DINode::DIFlags Flags, DIType *Ty) { + return DIDerivedType::get(VMContext, dwarf::DW_TAG_member, Name, File, + LineNumber, getNonCompileUnitScope(Scope), Ty, + SizeInBits, AlignInBits, OffsetInBits, None, Flags, + getConstantOrNull(Discriminant)); +} + DIDerivedType *DIBuilder::createBitFieldMemberType( DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, uint64_t SizeInBits, uint64_t OffsetInBits, uint64_t StorageOffsetInBits, @@ -458,6 +471,18 @@ DICompositeType *DIBuilder::createUnionType( return R; } +DICompositeType *DIBuilder::createVariantPart( + DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, + uint64_t SizeInBits, uint32_t AlignInBits, DINode::DIFlags Flags, + DIDerivedType *Discriminator, DINodeArray Elements, StringRef UniqueIdentifier) { + auto *R = DICompositeType::get( + VMContext, dwarf::DW_TAG_variant_part, Name, File, LineNumber, + getNonCompileUnitScope(Scope), nullptr, SizeInBits, AlignInBits, 0, Flags, + Elements, 0, nullptr, nullptr, UniqueIdentifier, Discriminator); + trackIfUnresolved(R); + return R; +} + DISubroutineType *DIBuilder::createSubroutineType(DITypeRefArray ParameterTypes, DINode::DIFlags Flags, unsigned CC) { diff --git a/lib/IR/DebugInfoMetadata.cpp b/lib/IR/DebugInfoMetadata.cpp index 75ddd47b2591..7720843e735a 100644 --- a/lib/IR/DebugInfoMetadata.cpp +++ b/lib/IR/DebugInfoMetadata.cpp @@ -296,17 +296,18 @@ DICompositeType *DICompositeType::getImpl( unsigned Line, Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, DIFlags Flags, Metadata *Elements, unsigned RuntimeLang, Metadata *VTableHolder, - Metadata *TemplateParams, MDString *Identifier, StorageType Storage, - bool ShouldCreate) { + Metadata *TemplateParams, MDString *Identifier, Metadata *Discriminator, + StorageType Storage, bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); // Keep this in sync with buildODRType. DEFINE_GETIMPL_LOOKUP( DICompositeType, (Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang, - VTableHolder, TemplateParams, Identifier)); + VTableHolder, TemplateParams, Identifier, Discriminator)); Metadata *Ops[] = {File, Scope, Name, BaseType, - Elements, VTableHolder, TemplateParams, Identifier}; + Elements, VTableHolder, TemplateParams, Identifier, + Discriminator}; DEFINE_GETIMPL_STORE(DICompositeType, (Tag, Line, RuntimeLang, SizeInBits, AlignInBits, OffsetInBits, Flags), Ops); @@ -317,7 +318,7 @@ DICompositeType *DICompositeType::buildODRType( Metadata *File, unsigned Line, Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, DIFlags Flags, Metadata *Elements, unsigned RuntimeLang, - Metadata *VTableHolder, Metadata *TemplateParams) { + Metadata *VTableHolder, Metadata *TemplateParams, Metadata *Discriminator) { assert(!Identifier.getString().empty() && "Expected valid identifier"); if (!Context.isODRUniquingDebugTypes()) return nullptr; @@ -326,7 +327,7 @@ DICompositeType *DICompositeType::buildODRType( return CT = DICompositeType::getDistinct( Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang, - VTableHolder, TemplateParams, &Identifier); + VTableHolder, TemplateParams, &Identifier, Discriminator); // Only mutate CT if it's a forward declaration and the new operands aren't. assert(CT->getRawIdentifier() == &Identifier && "Wrong ODR identifier?"); @@ -337,7 +338,8 @@ DICompositeType *DICompositeType::buildODRType( CT->mutate(Tag, Line, RuntimeLang, SizeInBits, AlignInBits, OffsetInBits, Flags); Metadata *Ops[] = {File, Scope, Name, BaseType, - Elements, VTableHolder, TemplateParams, &Identifier}; + Elements, VTableHolder, TemplateParams, &Identifier, + Discriminator}; assert((std::end(Ops) - std::begin(Ops)) == (int)CT->getNumOperands() && "Mismatched number of operands"); for (unsigned I = 0, E = CT->getNumOperands(); I != E; ++I) @@ -351,7 +353,7 @@ DICompositeType *DICompositeType::getODRType( Metadata *File, unsigned Line, Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, DIFlags Flags, Metadata *Elements, unsigned RuntimeLang, - Metadata *VTableHolder, Metadata *TemplateParams) { + Metadata *VTableHolder, Metadata *TemplateParams, Metadata *Discriminator) { assert(!Identifier.getString().empty() && "Expected valid identifier"); if (!Context.isODRUniquingDebugTypes()) return nullptr; @@ -360,7 +362,7 @@ DICompositeType *DICompositeType::getODRType( CT = DICompositeType::getDistinct( Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang, VTableHolder, - TemplateParams, &Identifier); + TemplateParams, &Identifier, Discriminator); return CT; } diff --git a/lib/IR/LLVMContextImpl.h b/lib/IR/LLVMContextImpl.h index f41acfa8ea9c..c43136279902 100644 --- a/lib/IR/LLVMContextImpl.h +++ b/lib/IR/LLVMContextImpl.h @@ -484,18 +484,20 @@ template <> struct MDNodeKeyImpl { Metadata *VTableHolder; Metadata *TemplateParams; MDString *Identifier; + Metadata *Discriminator; MDNodeKeyImpl(unsigned Tag, MDString *Name, Metadata *File, unsigned Line, Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, unsigned Flags, Metadata *Elements, unsigned RuntimeLang, Metadata *VTableHolder, Metadata *TemplateParams, - MDString *Identifier) + MDString *Identifier, Metadata *Discriminator) : Tag(Tag), Name(Name), File(File), Line(Line), Scope(Scope), BaseType(BaseType), SizeInBits(SizeInBits), OffsetInBits(OffsetInBits), AlignInBits(AlignInBits), Flags(Flags), Elements(Elements), RuntimeLang(RuntimeLang), VTableHolder(VTableHolder), - TemplateParams(TemplateParams), Identifier(Identifier) {} + TemplateParams(TemplateParams), Identifier(Identifier), + Discriminator(Discriminator) {} MDNodeKeyImpl(const DICompositeType *N) : Tag(N->getTag()), Name(N->getRawName()), File(N->getRawFile()), Line(N->getLine()), Scope(N->getRawScope()), @@ -504,7 +506,8 @@ template <> struct MDNodeKeyImpl { Flags(N->getFlags()), Elements(N->getRawElements()), RuntimeLang(N->getRuntimeLang()), VTableHolder(N->getRawVTableHolder()), TemplateParams(N->getRawTemplateParams()), - Identifier(N->getRawIdentifier()) {} + Identifier(N->getRawIdentifier()), + Discriminator(N->getRawDiscriminator()) {} bool isKeyOf(const DICompositeType *RHS) const { return Tag == RHS->getTag() && Name == RHS->getRawName() && @@ -517,7 +520,8 @@ template <> struct MDNodeKeyImpl { RuntimeLang == RHS->getRuntimeLang() && VTableHolder == RHS->getRawVTableHolder() && TemplateParams == RHS->getRawTemplateParams() && - Identifier == RHS->getRawIdentifier(); + Identifier == RHS->getRawIdentifier() && + Discriminator == RHS->getRawDiscriminator(); } unsigned getHashValue() const { diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index 1754f7d45011..4dba1a0e211c 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -927,7 +927,8 @@ void Verifier::visitDICompositeType(const DICompositeType &N) { N.getTag() == dwarf::DW_TAG_structure_type || N.getTag() == dwarf::DW_TAG_union_type || N.getTag() == dwarf::DW_TAG_enumeration_type || - N.getTag() == dwarf::DW_TAG_class_type, + N.getTag() == dwarf::DW_TAG_class_type || + N.getTag() == dwarf::DW_TAG_variant_part, "invalid tag", &N); AssertDI(isScope(N.getRawScope()), "invalid scope", &N, N.getRawScope()); @@ -948,6 +949,11 @@ void Verifier::visitDICompositeType(const DICompositeType &N) { AssertDI(N.getFile() && !N.getFile()->getFilename().empty(), "class/union requires a filename", &N, N.getFile()); } + + if (auto *D = N.getRawDiscriminator()) { + AssertDI(isa(D) && N.getTag() == dwarf::DW_TAG_variant_part, + "discriminator can only appear on variant part"); + } } void Verifier::visitDISubroutineType(const DISubroutineType &N) { diff --git a/test/Assembler/debug-info.ll b/test/Assembler/debug-info.ll index 6be3a308e627..393d6fa4d210 100644 --- a/test/Assembler/debug-info.ll +++ b/test/Assembler/debug-info.ll @@ -1,8 +1,8 @@ ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s ; RUN: verify-uselistorder %s -; CHECK: !named = !{!0, !0, !1, !2, !3, !4, !5, !6, !7, !8, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !27, !28, !29, !30, !31, !32, !33, !33} -!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !28, !29, !30, !31, !32, !33, !34, !35, !36, !37} +; CHECK: !named = !{!0, !0, !1, !2, !3, !4, !5, !6, !7, !8, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !27, !28, !29, !30, !31, !32, !33, !34, !35, !36} +!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !28, !29, !30, !31, !32, !33, !34, !35, !36, !38, !39, !40} ; CHECK: !0 = !DISubrange(count: 3) ; CHECK-NEXT: !1 = !DISubrange(count: 3, lowerBound: 4) @@ -85,3 +85,10 @@ !35 = !DIFile(filename: "file", directory: "dir", checksumkind: CSK_MD5, checksum: "000102030405060708090a0b0c0d0e0f") !36 = !DIFile(filename: "file", directory: "dir", checksumkind: CSK_None) !37 = !DIFile(filename: "file", directory: "dir", checksumkind: CSK_None, checksum: "") + +; CHECK-NEXT: !34 = !DICompositeType(tag: DW_TAG_variant_part, name: "A", scope: !14, size: 64) +; CHECK-NEXT: !35 = !DIDerivedType(tag: DW_TAG_member, scope: !34, baseType: !36, size: 64, align: 64, flags: DIFlagArtificial) +; CHECK-NEXT: !36 = !DIBasicType(name: "u64", size: 64, encoding: DW_ATE_unsigned) +!38 = !DICompositeType(tag: DW_TAG_variant_part, name: "A", scope: !16, size: 64, discriminator: !39) +!39 = !DIDerivedType(tag: DW_TAG_member, scope: !38, baseType: !40, size: 64, align: 64, flags: DIFlagArtificial) +!40 = !DIBasicType(name: "u64", size: 64, encoding: DW_ATE_unsigned) diff --git a/test/DebugInfo/Generic/discriminated-union.ll b/test/DebugInfo/Generic/discriminated-union.ll new file mode 100644 index 000000000000..aebbe0e6c4c6 --- /dev/null +++ b/test/DebugInfo/Generic/discriminated-union.ll @@ -0,0 +1,80 @@ +; REQUIRES: object-emission + +; RUN: %llc_dwarf -O0 -filetype=obj < %s > %t +; RUN: llvm-dwarfdump -v -debug-info %t | FileCheck %s + +; Check for a variant part that has two members, one of which has a +; discriminant value. + +; CHECK: DW_TAG_variant_part +; CHECK-NOT: TAG +; CHECK: DW_AT_discr [DW_FORM_ref4] (cu + {{0x[0-9a-fA-F]+}} => {[[OFFSET:0x[0-9a-fA-F]+]]}) +; CHECK-NOT: TAG +; CHECK: [[OFFSET]]: DW_TAG_member +; CHECK: DW_AT_type +; CHECK: DW_AT_alignment +; CHECK: DW_AT_data_member_location [DW_FORM_data1] (0x00) +; CHECK: DW_AT_artificial [DW_FORM_flag_present] (true) +; CHECK: DW_TAG_variant +; CHECK: DW_TAG_member +; CHECK: DW_AT_type +; CHECK: DW_AT_alignment +; CHECK: DW_AT_data_member_location [DW_FORM_data1] (0x00) +; CHECK: DW_TAG_variant +; CHECK: DW_AT_discr_value [DW_FORM_data1] (0x00) +; CHECK: DW_TAG_member +; CHECK: DW_AT_type +; CHECK: DW_AT_alignment +; CHECK: DW_AT_data_member_location [DW_FORM_data1] (0x00) + +%F = type { [0 x i8], {}*, [8 x i8] } +%"F::Nope" = type {} + +define internal void @_ZN2e34main17h934ff72f9a38d4bbE() unnamed_addr #0 !dbg !5 { +start: + %qq = alloca %F, align 8 + call void @llvm.dbg.declare(metadata %F* %qq, metadata !10, metadata !28), !dbg !29 + %0 = bitcast %F* %qq to {}**, !dbg !29 + store {}* null, {}** %0, !dbg !29 + %1 = bitcast %F* %qq to %"F::Nope"*, !dbg !29 + ret void, !dbg !30 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #0 + +attributes #0 = { nounwind uwtable } + +!llvm.module.flags = !{!0, !1} +!llvm.dbg.cu = !{!2} + +!0 = !{i32 1, !"PIE Level", i32 2} +!1 = !{i32 2, !"Debug Info Version", i32 3} +!2 = distinct !DICompileUnit(language: DW_LANG_Rust, file: !3, producer: "clang LLVM (rustc version 1.24.0-dev)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4) +!3 = !DIFile(filename: "e3.rs", directory: "/home/tromey/Rust") +!4 = !{} +!5 = distinct !DISubprogram(name: "main", linkageName: "_ZN2e34mainE", scope: !6, file: !3, line: 2, type: !8, isLocal: true, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped | DIFlagMainSubprogram, isOptimized: false, unit: !2, templateParams: !4, variables: !4) +!6 = !DINamespace(name: "e3", scope: null) +!7 = !DIFile(filename: "", directory: "") +!8 = !DISubroutineType(types: !9) +!9 = !{null} +!10 = !DILocalVariable(name: "qq", scope: !11, file: !3, line: 3, type: !12, align: 8) +!11 = distinct !DILexicalBlock(scope: !5, file: !3, line: 3, column: 4) +!12 = !DICompositeType(tag: DW_TAG_structure_type, name: "F", scope: !6, file: !7, size: 128, align: 64, elements: !13, identifier: "7ce1efff6b82281ab9ceb730566e7e20") +!13 = !{!14} +!14 = !DICompositeType(tag: DW_TAG_variant_part, name: "", scope: !12, file: !7, size: 128, align: 64, elements: !16, identifier: "7ce1efff6b82281ab9ceb730566e7e20", discriminator: !15) +!15 = !DIDerivedType(tag: DW_TAG_member, scope: !14, file: !7, baseType: !27, size: 64, align: 64, flags: DIFlagArtificial) +!16 = !{!17, !24} +!17 = !DIDerivedType(tag: DW_TAG_member, scope: !14, file: !7, baseType: !18, size: 128, align: 64) +!18 = !DICompositeType(tag: DW_TAG_structure_type, name: "Yep", scope: !12, file: !7, size: 128, align: 64, elements: !19, identifier: "7ce1efff6b82281ab9ceb730566e7e20::Yep") +!19 = !{!20, !22} +!20 = !DIDerivedType(tag: DW_TAG_member, name: "__0", scope: !18, file: !7, baseType: !21, size: 8, align: 8, offset: 64) +!21 = !DIBasicType(name: "u8", size: 8, encoding: DW_ATE_unsigned) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "__1", scope: !18, file: !7, baseType: !23, size: 64, align: 64) +!23 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "&u8", baseType: !21, size: 64, align: 64) +!24 = !DIDerivedType(tag: DW_TAG_member, scope: !14, file: !7, baseType: !25, size: 128, align: 64, extraData: i64 0) +!25 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nope", scope: !12, file: !7, size: 128, align: 64, elements: !4, identifier: "7ce1efff6b82281ab9ceb730566e7e20::Nope") +!27 = !DIBasicType(name: "u64", size: 64, encoding: DW_ATE_unsigned) +!28 = !DIExpression() +!29 = !DILocation(line: 3, scope: !11) +!30 = !DILocation(line: 4, scope: !5) diff --git a/test/DebugInfo/Generic/univariant-discriminated-union.ll b/test/DebugInfo/Generic/univariant-discriminated-union.ll new file mode 100644 index 000000000000..5fc1d7ad95a6 --- /dev/null +++ b/test/DebugInfo/Generic/univariant-discriminated-union.ll @@ -0,0 +1,65 @@ +; REQUIRES: object-emission + +; RUN: %llc_dwarf -O0 -filetype=obj < %s > %t +; RUN: llvm-dwarfdump -v -debug-info %t | FileCheck %s + +; Check for a univariant discriminated union -- that is, a variant +; part without a discriminant and with just a single variant. + +; CHECK: DW_TAG_variant_part +; CHECK-NOT: DW_AT_discr +; CHECK: DW_TAG_variant +; CHECK: DW_TAG_member +; CHECK: DW_AT_type +; CHECK: DW_AT_alignment +; CHECK: DW_AT_data_member_location [DW_FORM_data1] (0x00) + +%F = type { [0 x i8], {}*, [8 x i8] } +%"F::Nope" = type {} + +define internal void @_ZN2e34main17h934ff72f9a38d4bbE() unnamed_addr #0 !dbg !5 { +start: + %qq = alloca %F, align 8 + call void @llvm.dbg.declare(metadata %F* %qq, metadata !10, metadata !28), !dbg !29 + %0 = bitcast %F* %qq to {}**, !dbg !29 + store {}* null, {}** %0, !dbg !29 + %1 = bitcast %F* %qq to %"F::Nope"*, !dbg !29 + ret void, !dbg !30 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #0 + +attributes #0 = { nounwind uwtable } + +!llvm.module.flags = !{!0, !1} +!llvm.dbg.cu = !{!2} + +!0 = !{i32 1, !"PIE Level", i32 2} +!1 = !{i32 2, !"Debug Info Version", i32 3} +!2 = distinct !DICompileUnit(language: DW_LANG_Rust, file: !3, producer: "clang LLVM (rustc version 1.24.0-dev)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4) +!3 = !DIFile(filename: "e3.rs", directory: "/home/tromey/Rust") +!4 = !{} +!5 = distinct !DISubprogram(name: "main", linkageName: "_ZN2e34mainE", scope: !6, file: !3, line: 2, type: !8, isLocal: true, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped | DIFlagMainSubprogram, isOptimized: false, unit: !2, templateParams: !4, variables: !4) +!6 = !DINamespace(name: "e3", scope: null) +!7 = !DIFile(filename: "", directory: "") +!8 = !DISubroutineType(types: !9) +!9 = !{null} +!10 = !DILocalVariable(name: "qq", scope: !11, file: !3, line: 3, type: !12, align: 8) +!11 = distinct !DILexicalBlock(scope: !5, file: !3, line: 3, column: 4) +!12 = !DICompositeType(tag: DW_TAG_structure_type, name: "F", scope: !6, file: !7, size: 128, align: 64, elements: !13, identifier: "7ce1efff6b82281ab9ceb730566e7e20") +!13 = !{!14} +!14 = !DICompositeType(tag: DW_TAG_variant_part, name: "", scope: !12, file: !7, size: 128, align: 64, elements: !16, identifier: "7ce1efff6b82281ab9ceb730566e7e20") + +!16 = !{!17} +!17 = !DIDerivedType(tag: DW_TAG_member, scope: !14, file: !7, baseType: !18, size: 128, align: 64) +!18 = !DICompositeType(tag: DW_TAG_structure_type, name: "Yep", scope: !12, file: !7, size: 128, align: 64, elements: !19, identifier: "7ce1efff6b82281ab9ceb730566e7e20::Yep") +!19 = !{!20, !22} +!20 = !DIDerivedType(tag: DW_TAG_member, name: "__0", scope: !18, file: !7, baseType: !21, size: 8, align: 8, offset: 64) +!21 = !DIBasicType(name: "u8", size: 8, encoding: DW_ATE_unsigned) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "__1", scope: !18, file: !7, baseType: !23, size: 64, align: 64) +!23 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "&u8", baseType: !21, size: 64, align: 64) + +!28 = !DIExpression() +!29 = !DILocation(line: 3, scope: !11) +!30 = !DILocation(line: 4, scope: !5) diff --git a/test/Verifier/variant-part.ll b/test/Verifier/variant-part.ll new file mode 100644 index 000000000000..d3318fe141e6 --- /dev/null +++ b/test/Verifier/variant-part.ll @@ -0,0 +1,8 @@ +; RUN: not llvm-as -disable-output <%s 2>&1 | FileCheck %s + +!named = !{!0} +!0 = !DICompositeType(tag: DW_TAG_structure_type, name: "A", size: 64, discriminator: !1) +!1 = !DIDerivedType(tag: DW_TAG_member, scope: !0, baseType: !3, size: 64, align: 64, flags: DIFlagArtificial) +!3 = !DIBasicType(name: "u64", size: 64, encoding: DW_ATE_unsigned) + +; CHECK: discriminator can only appear on variant part diff --git a/unittests/IR/DebugTypeODRUniquingTest.cpp b/unittests/IR/DebugTypeODRUniquingTest.cpp index 7eb08e24b408..af77091221c3 100644 --- a/unittests/IR/DebugTypeODRUniquingTest.cpp +++ b/unittests/IR/DebugTypeODRUniquingTest.cpp @@ -30,7 +30,7 @@ TEST(DebugTypeODRUniquingTest, getODRType) { // Without a type map, this should return null. EXPECT_FALSE(DICompositeType::getODRType( Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, - nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr)); + nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr, nullptr)); // Enable the mapping. There still shouldn't be a type. Context.enableDebugTypeODRUniquing(); @@ -39,7 +39,7 @@ TEST(DebugTypeODRUniquingTest, getODRType) { // Create some ODR-uniqued type. auto &CT = *DICompositeType::getODRType( Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, - nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr); + nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr, nullptr); EXPECT_EQ(UUID.getString(), CT.getIdentifier()); // Check that we get it back, even if we change a field. @@ -47,12 +47,12 @@ TEST(DebugTypeODRUniquingTest, getODRType) { EXPECT_EQ(&CT, DICompositeType::getODRType( Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, - nullptr, nullptr)); + nullptr, nullptr, nullptr)); EXPECT_EQ(&CT, DICompositeType::getODRType( Context, UUID, dwarf::DW_TAG_class_type, MDString::get(Context, "name"), nullptr, 0, nullptr, nullptr, 0, - 0, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr)); + 0, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr, nullptr)); // Check that it's discarded with the type map. Context.disableDebugTypeODRUniquing(); @@ -71,32 +71,32 @@ TEST(DebugTypeODRUniquingTest, buildODRType) { MDString &UUID = *MDString::get(Context, "Type"); auto &CT = *DICompositeType::buildODRType( Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, - nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr); + nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr, nullptr); EXPECT_EQ(&CT, DICompositeType::getODRTypeIfExists(Context, UUID)); EXPECT_EQ(dwarf::DW_TAG_class_type, CT.getTag()); // Update with another forward decl. This should be a no-op. EXPECT_EQ(&CT, DICompositeType::buildODRType( Context, UUID, dwarf::DW_TAG_structure_type, nullptr, nullptr, 0, nullptr, - nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr)); + nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr, nullptr)); EXPECT_EQ(dwarf::DW_TAG_class_type, CT.getTag()); // Update with a definition. This time we should see a change. EXPECT_EQ(&CT, DICompositeType::buildODRType( Context, UUID, dwarf::DW_TAG_structure_type, nullptr, nullptr, 0, nullptr, nullptr, 0, 0, 0, DINode::FlagZero, - nullptr, 0, nullptr, nullptr)); + nullptr, 0, nullptr, nullptr, nullptr)); EXPECT_EQ(dwarf::DW_TAG_structure_type, CT.getTag()); // Further updates should be ignored. EXPECT_EQ(&CT, DICompositeType::buildODRType( Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, - nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr)); + nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr, nullptr)); EXPECT_EQ(dwarf::DW_TAG_structure_type, CT.getTag()); EXPECT_EQ(&CT, DICompositeType::buildODRType( Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, - nullptr, nullptr)); + nullptr, nullptr, nullptr)); EXPECT_EQ(dwarf::DW_TAG_structure_type, CT.getTag()); } @@ -108,7 +108,7 @@ TEST(DebugTypeODRUniquingTest, buildODRTypeFields) { MDString &UUID = *MDString::get(Context, "UUID"); auto &CT = *DICompositeType::buildODRType( Context, UUID, 0, nullptr, nullptr, 0, nullptr, nullptr, 0, 0, 0, - DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr); + DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr, nullptr); // Create macros for running through all the fields except Identifier and Flags. #define FOR_EACH_MDFIELD() \ @@ -141,7 +141,7 @@ TEST(DebugTypeODRUniquingTest, buildODRTypeFields) { DICompositeType::buildODRType( Context, UUID, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, OffsetInBits, DINode::FlagArtificial, - Elements, RuntimeLang, VTableHolder, TemplateParams)); + Elements, RuntimeLang, VTableHolder, TemplateParams, nullptr)); // Confirm that all the right fields got updated. #define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.getRaw##X()); diff --git a/unittests/IR/MetadataTest.cpp b/unittests/IR/MetadataTest.cpp index 672de55fbdea..f5fc74bbe142 100644 --- a/unittests/IR/MetadataTest.cpp +++ b/unittests/IR/MetadataTest.cpp @@ -1330,6 +1330,51 @@ TEST_F(DICompositeTypeTest, replaceOperands) { EXPECT_EQ(nullptr, N->getTemplateParams().get()); } +TEST_F(DICompositeTypeTest, variant_part) { + unsigned Tag = dwarf::DW_TAG_variant_part; + StringRef Name = "some name"; + DIFile *File = getFile(); + unsigned Line = 1; + DIScope *Scope = getSubprogram(); + DIType *BaseType = getCompositeType(); + uint64_t SizeInBits = 2; + uint32_t AlignInBits = 3; + uint64_t OffsetInBits = 4; + DINode::DIFlags Flags = static_cast(5); + unsigned RuntimeLang = 6; + StringRef Identifier = "some id"; + DIDerivedType *Discriminator = cast(getDerivedType()); + DIDerivedType *Discriminator2 = cast(getDerivedType()); + + EXPECT_NE(Discriminator, Discriminator2); + + auto *N = DICompositeType::get( + Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, nullptr, RuntimeLang, nullptr, nullptr, Identifier, + Discriminator); + + // Test the hashing. + auto *Same = DICompositeType::get( + Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, nullptr, RuntimeLang, nullptr, nullptr, Identifier, + Discriminator); + auto *Other = DICompositeType::get( + Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, nullptr, RuntimeLang, nullptr, nullptr, Identifier, + Discriminator2); + auto *NoDisc = DICompositeType::get( + Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, nullptr, RuntimeLang, nullptr, nullptr, Identifier, + nullptr); + + EXPECT_EQ(N, Same); + EXPECT_NE(Same, Other); + EXPECT_NE(Same, NoDisc); + EXPECT_NE(Other, NoDisc); + + EXPECT_EQ(N->getDiscriminator(), Discriminator); +} + typedef MetadataTest DISubroutineTypeTest; TEST_F(DISubroutineTypeTest, get) {