//===- DebugTypeODRUniquingTest.cpp - Debug type ODR uniquing tests -------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "llvm/IR/LLVMContext.h" #include "llvm/IR/DebugInfoMetadata.h" #include "gtest/gtest.h" using namespace llvm; namespace { TEST(DebugTypeODRUniquingTest, enableDebugTypeODRUniquing) { LLVMContext Context; EXPECT_FALSE(Context.isODRUniquingDebugTypes()); Context.enableDebugTypeODRUniquing(); EXPECT_TRUE(Context.isODRUniquingDebugTypes()); Context.disableDebugTypeODRUniquing(); EXPECT_FALSE(Context.isODRUniquingDebugTypes()); } TEST(DebugTypeODRUniquingTest, getODRType) { LLVMContext Context; MDString &UUID = *MDString::get(Context, "string"); // 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, 0, nullptr, 0, nullptr, nullptr)); // Enable the mapping. There still shouldn't be a type. Context.enableDebugTypeODRUniquing(); EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID)); // Create some ODR-uniqued type. auto &CT = *DICompositeType::getODRType( Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, nullptr, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr); EXPECT_EQ(UUID.getString(), CT.getIdentifier()); // Check that we get it back, even if we change a field. EXPECT_EQ(&CT, DICompositeType::getODRTypeIfExists(Context, UUID)); EXPECT_EQ( &CT, DICompositeType::getODRType(Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, nullptr, 0, 0, 0, 0, nullptr, 0, 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, 0, nullptr, 0, nullptr, nullptr)); // Check that it's discarded with the type map. Context.disableDebugTypeODRUniquing(); EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID)); // And it shouldn't magically reappear... Context.enableDebugTypeODRUniquing(); EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID)); } TEST(DebugTypeODRUniquingTest, buildODRType) { LLVMContext Context; Context.enableDebugTypeODRUniquing(); // Build an ODR type that's a forward decl. 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); 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)); 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, 0, nullptr, 0, 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)); 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, 0, nullptr, 0, nullptr, nullptr)); EXPECT_EQ(dwarf::DW_TAG_structure_type, CT.getTag()); } TEST(DebugTypeODRUniquingTest, buildODRTypeFields) { LLVMContext Context; Context.enableDebugTypeODRUniquing(); // Build an ODR type that's a forward decl with no other fields set. 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); // Create macros for running through all the fields except Identifier and Flags. #define FOR_EACH_MDFIELD() \ DO_FOR_FIELD(Name) \ DO_FOR_FIELD(File) \ DO_FOR_FIELD(Scope) \ DO_FOR_FIELD(BaseType) \ DO_FOR_FIELD(Elements) \ DO_FOR_FIELD(VTableHolder) \ DO_FOR_FIELD(TemplateParams) #define FOR_EACH_INLINEFIELD() \ DO_FOR_FIELD(Tag) \ DO_FOR_FIELD(Line) \ DO_FOR_FIELD(SizeInBits) \ DO_FOR_FIELD(AlignInBits) \ DO_FOR_FIELD(OffsetInBits) \ DO_FOR_FIELD(RuntimeLang) // Create all the fields. #define DO_FOR_FIELD(X) auto *X = MDString::get(Context, #X); FOR_EACH_MDFIELD(); #undef DO_FOR_FIELD unsigned NonZeroInit = 0; #define DO_FOR_FIELD(X) auto X = ++NonZeroInit; FOR_EACH_INLINEFIELD(); #undef DO_FOR_FIELD // Replace all the fields with new values that are distinct from each other. EXPECT_EQ(&CT, DICompositeType::buildODRType( Context, UUID, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, OffsetInBits, DINode::FlagArtificial, Elements, RuntimeLang, VTableHolder, TemplateParams)); // Confirm that all the right fields got updated. #define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.getRaw##X()); FOR_EACH_MDFIELD(); #undef DO_FOR_FIELD #undef FOR_EACH_MDFIELD #define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.get##X()); FOR_EACH_INLINEFIELD(); #undef DO_FOR_FIELD #undef FOR_EACH_INLINEFIELD EXPECT_EQ(DINode::FlagArtificial, CT.getFlags()); EXPECT_EQ(&UUID, CT.getRawIdentifier()); } } // end namespace