mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
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 llvm-svn: 324426
This commit is contained in:
parent
a8bbefe904
commit
821c2290a5
@ -258,6 +258,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.
|
||||
@ -379,6 +400,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.
|
||||
|
@ -847,6 +847,12 @@ public:
|
||||
return C->getValue();
|
||||
return nullptr;
|
||||
}
|
||||
Constant *getDiscriminantValue() const {
|
||||
assert(getTag() == dwarf::DW_TAG_member && !isStaticMember());
|
||||
if (auto *C = cast_or_null<ConstantAsMetadata>(getExtraData()))
|
||||
return C->getValue();
|
||||
return nullptr;
|
||||
}
|
||||
/// @}
|
||||
|
||||
static bool classof(const Metadata *MD) {
|
||||
@ -889,12 +895,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,
|
||||
@ -902,14 +909,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:
|
||||
@ -920,10 +928,10 @@ public:
|
||||
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,
|
||||
@ -931,10 +939,11 @@ public:
|
||||
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(); }
|
||||
|
||||
@ -951,7 +960,7 @@ public:
|
||||
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);
|
||||
|
||||
@ -970,7 +979,7 @@ public:
|
||||
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 {
|
||||
@ -988,6 +997,8 @@ public:
|
||||
Metadata *getRawVTableHolder() const { return getOperand(5); }
|
||||
Metadata *getRawTemplateParams() const { return getOperand(6); }
|
||||
MDString *getRawIdentifier() const { return getOperandAs<MDString>(7); }
|
||||
Metadata *getRawDiscriminator() const { return getOperand(8); }
|
||||
DIDerivedType *getDiscriminator() const { return getOperandAs<DIDerivedType>(8); }
|
||||
|
||||
/// Replace operands.
|
||||
///
|
||||
|
@ -4156,7 +4156,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
|
||||
|
||||
@ -4166,7 +4167,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;
|
||||
}
|
||||
@ -4177,7 +4178,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;
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
@ -563,8 +553,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();
|
||||
|
@ -1246,7 +1246,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
|
||||
@ -1269,6 +1269,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
|
||||
@ -1289,13 +1290,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)
|
||||
|
@ -1526,6 +1526,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();
|
||||
|
@ -946,9 +946,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) {
|
||||
@ -962,6 +977,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<ConstantInt>(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);
|
||||
}
|
||||
@ -981,6 +1008,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<DICompositeType>(Element)) {
|
||||
if (Composite->getTag() == dwarf::DW_TAG_variant_part) {
|
||||
DIE &VariantPart = createAndAddDIE(Composite->getTag(), Buffer);
|
||||
constructTypeDIE(VariantPart, Composite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1430,7 +1462,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())
|
||||
@ -1535,6 +1567,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) {
|
||||
|
@ -341,7 +341,7 @@ private:
|
||||
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,
|
||||
|
@ -1691,6 +1691,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 << ")";
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -305,17 +305,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);
|
||||
@ -326,7 +327,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;
|
||||
@ -335,7 +336,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?");
|
||||
@ -346,7 +347,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)
|
||||
@ -360,7 +362,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;
|
||||
@ -369,7 +371,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;
|
||||
}
|
||||
|
||||
|
@ -499,18 +499,20 @@ template <> struct MDNodeKeyImpl<DICompositeType> {
|
||||
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()),
|
||||
@ -519,7 +521,8 @@ template <> struct MDNodeKeyImpl<DICompositeType> {
|
||||
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() &&
|
||||
@ -532,7 +535,8 @@ template <> struct MDNodeKeyImpl<DICompositeType> {
|
||||
RuntimeLang == RHS->getRuntimeLang() &&
|
||||
VTableHolder == RHS->getRawVTableHolder() &&
|
||||
TemplateParams == RHS->getRawTemplateParams() &&
|
||||
Identifier == RHS->getRawIdentifier();
|
||||
Identifier == RHS->getRawIdentifier() &&
|
||||
Discriminator == RHS->getRawDiscriminator();
|
||||
}
|
||||
|
||||
unsigned getHashValue() const {
|
||||
|
@ -945,7 +945,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());
|
||||
@ -966,6 +967,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<DIDerivedType>(D) && N.getTag() == dwarf::DW_TAG_variant_part,
|
||||
"discriminator can only appear on variant part");
|
||||
}
|
||||
}
|
||||
|
||||
void Verifier::visitDISubroutineType(const DISubroutineType &N) {
|
||||
|
@ -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)
|
||||
|
80
test/DebugInfo/Generic/discriminated-union.ll
Normal file
80
test/DebugInfo/Generic/discriminated-union.ll
Normal file
@ -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: "<unknown>", 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)
|
65
test/DebugInfo/Generic/univariant-discriminated-union.ll
Normal file
65
test/DebugInfo/Generic/univariant-discriminated-union.ll
Normal file
@ -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: "<unknown>", 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)
|
8
test/Verifier/variant-part.ll
Normal file
8
test/Verifier/variant-part.ll
Normal file
@ -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
|
@ -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());
|
||||
|
@ -1355,6 +1355,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<DINode::DIFlags>(5);
|
||||
unsigned RuntimeLang = 6;
|
||||
StringRef Identifier = "some id";
|
||||
DIDerivedType *Discriminator = cast<DIDerivedType>(getDerivedType());
|
||||
DIDerivedType *Discriminator2 = cast<DIDerivedType>(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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user