diff options
-rw-r--r-- | comparison.cc | 12 | ||||
-rw-r--r-- | dwarf_processor.cc | 102 | ||||
-rw-r--r-- | equality.h | 11 | ||||
-rw-r--r-- | fingerprint.cc | 5 | ||||
-rw-r--r-- | graph.h | 8 | ||||
-rw-r--r-- | proto_reader.cc | 7 | ||||
-rw-r--r-- | proto_writer.cc | 4 | ||||
-rw-r--r-- | stable_hash.cc | 4 | ||||
-rw-r--r-- | stg.proto | 2 | ||||
-rw-r--r-- | substitution.h | 4 | ||||
-rw-r--r-- | test_cases/info_tests/variant/expected/negative_discriminant_rs.elf_stg | 79 | ||||
-rw-r--r-- | test_cases/info_tests/variant/expected/offset_discriminant_rs.elf_stg | 106 | ||||
-rw-r--r-- | test_cases/info_tests/variant/expected/optional_empty_rs.elf_stg | 65 | ||||
-rw-r--r-- | test_cases/info_tests/variant/expected/simple_rs.elf_stg | 112 | ||||
-rw-r--r-- | test_cases/info_tests/variant/expected/singleton_rs.elf_stg | 42 | ||||
-rw-r--r-- | test_cases/info_tests/variant/offset_discriminant.rs | 13 | ||||
-rw-r--r-- | test_cases/info_tests/variant/optional_empty.rs | 9 | ||||
-rw-r--r-- | test_cases/info_tests/variant/singleton.rs | 10 | ||||
-rw-r--r-- | type_normalisation.cc | 4 | ||||
-rw-r--r-- | unification.cc | 11 |
20 files changed, 579 insertions, 31 deletions
diff --git a/comparison.cc b/comparison.cc index 8e0dacb..0015fc8 100644 --- a/comparison.cc +++ b/comparison.cc @@ -570,9 +570,15 @@ Result Compare::operator()(const Variant& x1, const Variant& x2) { result.diff_.holds_changes = true; // Anonymous variants are not allowed. result.MaybeAddNodeDiff("bytesize", x1.bytesize, x2.bytesize); - const auto type_diff = - (*this)(x1.discriminant_type_id, x2.discriminant_type_id); - result.MaybeAddEdgeDiff("discriminant", type_diff); + if (x1.discriminant.has_value() && x2.discriminant.has_value()) { + const auto type_diff = + (*this)(x1.discriminant.value(), x2.discriminant.value()); + result.MaybeAddEdgeDiff("discriminant", type_diff); + } else if (x1.discriminant.has_value()) { + result.AddEdgeDiff("", Removed(x1.discriminant.value())); + } else if (x2.discriminant.has_value()) { + result.AddEdgeDiff("", Added(x2.discriminant.value())); + } CompareNodes(result, *this, x1.members, x2.members); return result; } diff --git a/dwarf_processor.cc b/dwarf_processor.cc index 9e84971..17fd682 100644 --- a/dwarf_processor.cc +++ b/dwarf_processor.cc @@ -496,6 +496,7 @@ class Processor { std::vector<Id> base_classes; std::vector<Id> members; std::vector<Id> methods; + std::optional<VariantAndMembers> variant_and_members = std::nullopt; for (auto& child : entry.GetChildren()) { auto child_tag = child.GetTag(); @@ -550,7 +551,11 @@ class Processor { // properly (resulting in no references to such DIEs). break; case DW_TAG_variant_part: - // TODO: Add a DWARF processor to process variants. + if (full_name.empty()) { + Die() << "Variant name should not be empty: " + << EntryToString(entry); + } + variant_and_members = GetVariantAndMembers(child); break; default: Die() << "Unexpected tag for child of struct/class/union: " @@ -558,6 +563,17 @@ class Processor { } } + if (variant_and_members.has_value()) { + // Add a Variant node since this entry represents a variant rather than a + // struct or union. + const Id id = + AddProcessedNode<Variant>(entry, full_name, GetByteSize(entry), + variant_and_members->discriminant, + std::move(variant_and_members->members)); + AddNamedTypeNode(id); + return; + } + if (entry.GetFlag(DW_AT_declaration) || !ShouldKeepDefinition(entry, type_name)) { // Declaration may have partial information about members or method. @@ -577,6 +593,37 @@ class Processor { } } + void ProcessVariantMember(Entry& entry) { + // TODO: Process signed discriminant values. + auto dw_discriminant_value = + entry.MaybeGetUnsignedConstant(DW_AT_discr_value); + auto discriminant_value = + dw_discriminant_value + ? std::optional(static_cast<int64_t>(*dw_discriminant_value)) + : std::nullopt; + + auto children = entry.GetChildren(); + if (children.size() != 1) { + Die() << "Unexpected number of children for variant member: " + << EntryToString(entry); + } + + auto child = children[0]; + if (child.GetTag() != DW_TAG_member) { + Die() << "Unexpected tag for variant member child: " + << Hex(child.GetTag()) << ", " << EntryToString(child); + } + if (GetDataBitOffset(child, 0, is_little_endian_binary_) != 0) { + Die() << "Unexpected data member location for variant member: " + << EntryToString(child); + } + + const std::string name = GetNameOrEmpty(child); + auto referred_type_id = GetReferredTypeId(GetReferredType(child)); + AddProcessedNode<VariantMember>(entry, name, discriminant_value, + referred_type_id); + } + void ProcessMember(Entry& entry) { const auto name = GetNameOrEmpty(entry); auto referred_type = GetReferredType(entry); @@ -726,6 +773,47 @@ class Processor { } } + struct VariantAndMembers { + std::optional<Id> discriminant; + std::vector<Id> members; + }; + + VariantAndMembers GetVariantAndMembers(Entry& entry) { + std::vector<Id> members; + std::optional<Id> discriminant = std::nullopt; + auto discriminant_entry = entry.MaybeGetReference(DW_AT_discr); + if (discriminant_entry.has_value()) { + discriminant = GetIdForEntry(*discriminant_entry); + ProcessMember(*discriminant_entry); + } + + for (auto& child : entry.GetChildren()) { + auto child_tag = child.GetTag(); + switch (child_tag) { + case DW_TAG_member: { + if (child.GetOffset() != discriminant_entry->GetOffset()) { + Die() << "Encountered rogue member for variant: " + << EntryToString(entry); + } + if (!child.GetFlag(DW_AT_artificial)) { + Die() << "Variant discriminant must be an artificial member: " + << EntryToString(child); + } + break; + } + case DW_TAG_variant: + members.push_back(GetIdForEntry(child)); + ProcessVariantMember(child); + break; + default: + Die() << "Unexpected tag for child of variant: " << Hex(child_tag) + << ", " << EntryToString(child); + } + } + return VariantAndMembers{.discriminant = discriminant, + .members = std::move(members)}; + } + struct NameWithContext { std::optional<Dwarf_Off> specification; std::optional<std::string> unscoped_name; @@ -901,10 +989,20 @@ class Processor { case DW_TAG_template_value_parameter: case DW_TAG_GNU_template_template_param: case DW_TAG_GNU_template_parameter_pack: - case DW_TAG_GNU_formal_parameter_pack: // We just skip these as neither GCC nor Clang seem to use them // properly (resulting in no references to such DIEs). break; + case DW_TAG_GNU_formal_parameter_pack: + // https://wiki.dwarfstd.org/C++0x_Variadic_templates.md + // + // As per this (rejected) proposal, GCC includes parameters as + // children of this DIE. + for (auto& child2 : child.GetChildren()) { + if (child2.GetTag() == DW_TAG_formal_parameter) { + parameters.push_back(GetReferredTypeId(GetReferredType(child2))); + } + } + break; default: Die() << "Unexpected tag for child of function: " << Hex(child_tag) << ", " << EntryToString(child); @@ -22,6 +22,7 @@ #include <cstddef> #include <map> +#include <optional> #include <vector> #include "graph.h" @@ -79,6 +80,14 @@ struct Equals { return result; } + bool operator()(const std::optional<Id>& opt1, + const std::optional<Id>& opt2) { + if (opt1.has_value() && opt2.has_value()) { + return (*this)(opt1.value(), opt2.value()); + } + return opt1.has_value() == opt2.has_value(); + } + bool operator()(const std::vector<Id>& ids1, const std::vector<Id>& ids2) { bool result = ids1.size() == ids2.size(); for (size_t ix = 0; result && ix < ids1.size(); ++ix) { @@ -197,7 +206,7 @@ struct Equals { bool operator()(const Variant& x1, const Variant& x2) { return x1.name == x2.name && x1.bytesize == x2.bytesize - && (*this)(x1.discriminant_type_id, x2.discriminant_type_id) + && (*this)(x1.discriminant, x2.discriminant) && (*this)(x1.members, x2.members); } diff --git a/fingerprint.cc b/fingerprint.cc index 05a4cdc..740e237 100644 --- a/fingerprint.cc +++ b/fingerprint.cc @@ -139,7 +139,10 @@ struct Hasher { } HashValue operator()(const Variant& x) { - auto h = hash('v', x.name, x.bytesize, (*this)(x.discriminant_type_id)); + auto h = hash('v', x.name, x.bytesize); + if (x.discriminant.has_value()) { + todo.insert(x.discriminant.value()); + } ToDo(x.members); return h; } @@ -249,16 +249,16 @@ struct Enumeration { }; struct Variant { - Variant(const std::string& name, uint64_t bytesize, Id discriminant_type_id, - const std::vector<Id>& members) + Variant(const std::string& name, uint64_t bytesize, + std::optional<Id> discriminant, const std::vector<Id>& members) : name(name), bytesize(bytesize), - discriminant_type_id(discriminant_type_id), + discriminant(discriminant), members(members) {} std::string name; uint64_t bytesize; - Id discriminant_type_id; + std::optional<Id> discriminant; std::vector<Id> members; }; diff --git a/proto_reader.cc b/proto_reader.cc index f2683ef..a83fd10 100644 --- a/proto_reader.cc +++ b/proto_reader.cc @@ -227,8 +227,11 @@ void Transformer::AddNode(const Enumeration& x) { } void Transformer::AddNode(const Variant& x) { - AddNode<stg::Variant>(GetId(x.id()), x.name(), x.bytesize(), - GetId(x.discriminant_type_id()), x.member_id()); + const auto& discriminant = x.has_discriminant() + ? std::make_optional(GetId(x.discriminant())) + : std::nullopt; + AddNode<stg::Variant>(GetId(x.id()), x.name(), x.bytesize(), discriminant, + x.member_id()); } void Transformer::AddNode(const Function& x) { diff --git a/proto_writer.cc b/proto_writer.cc index 919c5e8..16b1010 100644 --- a/proto_writer.cc +++ b/proto_writer.cc @@ -269,7 +269,9 @@ void Transform<MapId>::operator()(const stg::Variant& x, uint32_t id) { variant.set_id(id); variant.set_name(x.name); variant.set_bytesize(x.bytesize); - variant.set_discriminant_type_id((*this)(x.discriminant_type_id)); + if (x.discriminant.has_value()) { + variant.set_discriminant((*this)(x.discriminant.value())); + } for (const auto id : x.members) { variant.add_member_id((*this)(id)); } diff --git a/stable_hash.cc b/stable_hash.cc index a8f9366..5982072 100644 --- a/stable_hash.cc +++ b/stable_hash.cc @@ -161,7 +161,9 @@ HashValue StableHash::operator()(const Enumeration& x) { HashValue StableHash::operator()(const Variant& x) { HashValue hash = hash_('V', x.name, x.bytesize); - hash = DecayHashCombine<8>(hash, (*this)(x.discriminant_type_id)); + if (x.discriminant.has_value()) { + hash = DecayHashCombine<12>(hash, (*this)(x.discriminant.value())); + } return DecayHashCombine<2>(hash, DecayHashCombineInReverse<8>(x.members, *this)); } @@ -205,7 +205,7 @@ message Variant { fixed32 id = 1; string name = 2; uint64 bytesize = 3; - fixed32 discriminant_type_id = 4; + optional fixed32 discriminant = 4; repeated fixed32 member_id = 5; } diff --git a/substitution.h b/substitution.h index 863115f..43768cf 100644 --- a/substitution.h +++ b/substitution.h @@ -120,7 +120,9 @@ struct Substitute { } void operator()(Variant& x) { - Update(x.discriminant_type_id); + if (x.discriminant.has_value()) { + Update(x.discriminant.value()); + } Update(x.members); } diff --git a/test_cases/info_tests/variant/expected/negative_discriminant_rs.elf_stg b/test_cases/info_tests/variant/expected/negative_discriminant_rs.elf_stg index debfaf8..021539c 100644 --- a/test_cases/info_tests/variant/expected/negative_discriminant_rs.elf_stg +++ b/test_cases/info_tests/variant/expected/negative_discriminant_rs.elf_stg @@ -6,28 +6,95 @@ primitive { encoding: BOOLEAN bytesize: 0x00000001 } +primitive { + id: 0xd4bacb77 + name: "u32" + encoding: UNSIGNED_INTEGER + bytesize: 0x00000004 +} +primitive { + id: 0xedc43a15 + name: "i64" + encoding: SIGNED_INTEGER + bytesize: 0x00000008 +} +member { + id: 0x18ba9281 + type_id: 0xedc43a15 # i64 +} +member { + id: 0x976dcda7 + name: "__0" + type_id: 0xd4bacb77 # u32 + offset: 64 +} +variant_member { + id: 0x72c55dce + name: "MinusTwo" + discriminant_value: 65534 + type_id: 0xc8fb9972 +} +variant_member { + id: 0x528ee922 + name: "MinusOne" + discriminant_value: 65535 + type_id: 0xdfc84a58 +} +variant_member { + id: 0x27839c0b + name: "Zero" + discriminant_value: 0 + type_id: 0x5da8c8f1 +} struct_union { - id: 0x7a8d8645 + id: 0xdfc84a58 kind: STRUCT - name: "negative_discriminant::Foo" + name: "negative_discriminant::Foo::MinusOne" + definition { + bytesize: 16 + } +} +struct_union { + id: 0xc8fb9972 + kind: STRUCT + name: "negative_discriminant::Foo::MinusTwo" + definition { + bytesize: 16 + member_id: 0x976dcda7 # u32 __0 + } +} +struct_union { + id: 0x5da8c8f1 + kind: STRUCT + name: "negative_discriminant::Foo::Zero" definition { bytesize: 16 + member_id: 0x976dcda7 # u32 __0 } } +variant { + id: 0x298b726b + name: "negative_discriminant::Foo" + bytesize: 16 + discriminant: 0x18ba9281 + member_id: 0x72c55dce + member_id: 0x528ee922 + member_id: 0x27839c0b +} function { - id: 0xa0f30a2f + id: 0xb432b724 return_type_id: 0x62aebfd4 # bool - parameter_id: 0x7a8d8645 # struct negative_discriminant::Foo + parameter_id: 0x298b726b # variant negative_discriminant::Foo } elf_symbol { id: 0x0f95dadc name: "is_minus_one" is_defined: true symbol_type: FUNCTION - type_id: 0xa0f30a2f # bool(struct negative_discriminant::Foo) + type_id: 0xb432b724 # bool(variant negative_discriminant::Foo) full_name: "negative_discriminant::is_minus_one" } interface { id: 0x84ea5130 - symbol_id: 0x0f95dadc # bool negative_discriminant::is_minus_one(struct negative_discriminant::Foo) + symbol_id: 0x0f95dadc # bool negative_discriminant::is_minus_one(variant negative_discriminant::Foo) } diff --git a/test_cases/info_tests/variant/expected/offset_discriminant_rs.elf_stg b/test_cases/info_tests/variant/expected/offset_discriminant_rs.elf_stg new file mode 100644 index 0000000..e7ab069 --- /dev/null +++ b/test_cases/info_tests/variant/expected/offset_discriminant_rs.elf_stg @@ -0,0 +1,106 @@ +version: 0x00000002 +root_id: 0x84ea5130 # interface +primitive { + id: 0x384f7d7c + name: "char" + encoding: UTF + bytesize: 0x00000004 +} +primitive { + id: 0x62aebfd4 + name: "bool" + encoding: BOOLEAN + bytesize: 0x00000001 +} +primitive { + id: 0xd4bacb77 + name: "u32" + encoding: UNSIGNED_INTEGER + bytesize: 0x00000004 +} +member { + id: 0x16e523e2 + type_id: 0xd4bacb77 # u32 + offset: 32 +} +member { + id: 0x97813cf0 + name: "__0" + type_id: 0x384f7d7c # char +} +member { + id: 0xdbc0cd2f + name: "__1" + type_id: 0x384f7d7c # char + offset: 32 +} +variant_member { + id: 0x56b9f935 + name: "Two" + type_id: 0x573dc947 +} +variant_member { + id: 0x69cfc441 + name: "One" + discriminant_value: 1114112 + type_id: 0x988e2459 +} +variant_member { + id: 0x276cfc01 + name: "Zero" + discriminant_value: 1114113 + type_id: 0xb2cd8432 +} +struct_union { + id: 0x988e2459 + kind: STRUCT + name: "offset_discriminant::Foo::One" + definition { + bytesize: 8 + member_id: 0x97813cf0 # char __0 + } +} +struct_union { + id: 0x573dc947 + kind: STRUCT + name: "offset_discriminant::Foo::Two" + definition { + bytesize: 8 + member_id: 0x97813cf0 # char __0 + member_id: 0xdbc0cd2f # char __1 + } +} +struct_union { + id: 0xb2cd8432 + kind: STRUCT + name: "offset_discriminant::Foo::Zero" + definition { + bytesize: 8 + } +} +variant { + id: 0x82b2aa29 + name: "offset_discriminant::Foo" + bytesize: 8 + discriminant: 0x16e523e2 + member_id: 0x56b9f935 + member_id: 0x69cfc441 + member_id: 0x276cfc01 +} +function { + id: 0x9efcc134 + return_type_id: 0x62aebfd4 # bool + parameter_id: 0x82b2aa29 # variant offset_discriminant::Foo +} +elf_symbol { + id: 0x699cebd9 + name: "is_zero" + is_defined: true + symbol_type: FUNCTION + type_id: 0x9efcc134 # bool(variant offset_discriminant::Foo) + full_name: "offset_discriminant::is_zero" +} +interface { + id: 0x84ea5130 + symbol_id: 0x699cebd9 # bool offset_discriminant::is_zero(variant offset_discriminant::Foo) +} diff --git a/test_cases/info_tests/variant/expected/optional_empty_rs.elf_stg b/test_cases/info_tests/variant/expected/optional_empty_rs.elf_stg new file mode 100644 index 0000000..0584271 --- /dev/null +++ b/test_cases/info_tests/variant/expected/optional_empty_rs.elf_stg @@ -0,0 +1,65 @@ +version: 0x00000002 +root_id: 0x84ea5130 # interface +primitive { + id: 0x62aebfd4 + name: "bool" + encoding: BOOLEAN + bytesize: 0x00000001 +} +member { + id: 0x9758c0a4 + name: "__0" + type_id: 0xe1b3299b # variant optional_empty::Empty +} +variant_member { + id: 0x5212c510 + name: "None" + type_id: 0x3d2f2a96 +} +variant_member { + id: 0x3107bf38 + name: "Some" + type_id: 0x0148ce39 +} +struct_union { + id: 0x3d2f2a96 + kind: STRUCT + name: "core::option::Option<optional_empty::Empty>::None" + definition { + } +} +struct_union { + id: 0x0148ce39 + kind: STRUCT + name: "core::option::Option<optional_empty::Empty>::Some" + definition { + member_id: 0x9758c0a4 # variant optional_empty::Empty __0 + } +} +variant { + id: 0xc03763b2 + name: "core::option::Option<optional_empty::Empty>" + member_id: 0x5212c510 + member_id: 0x3107bf38 +} +variant { + id: 0xe1b3299b + name: "optional_empty::Empty" +} +function { + id: 0x8e5db352 + return_type_id: 0x62aebfd4 # bool + parameter_id: 0xc03763b2 # variant core::option::Option<optional_empty::Empty> +} +elf_symbol { + id: 0xbc9edef7 + name: "is_none" + is_defined: true + symbol_type: FUNCTION + type_id: 0x8e5db352 # bool(variant core::option::Option<optional_empty::Empty>) + full_name: "optional_empty::is_none" +} +interface { + id: 0x84ea5130 + symbol_id: 0xbc9edef7 # bool optional_empty::is_none(variant core::option::Option<optional_empty::Empty>) +} diff --git a/test_cases/info_tests/variant/expected/simple_rs.elf_stg b/test_cases/info_tests/variant/expected/simple_rs.elf_stg index 4621cf8..8473682 100644 --- a/test_cases/info_tests/variant/expected/simple_rs.elf_stg +++ b/test_cases/info_tests/variant/expected/simple_rs.elf_stg @@ -1,33 +1,133 @@ version: 0x00000002 root_id: 0x84ea5130 # interface primitive { + id: 0x2d2f93e0 + name: "u8" + encoding: UNSIGNED_INTEGER + bytesize: 0x00000001 +} +primitive { + id: 0x47ea5d8b + name: "i16" + encoding: SIGNED_INTEGER + bytesize: 0x00000002 +} +primitive { id: 0x62aebfd4 name: "bool" encoding: BOOLEAN bytesize: 0x00000001 } +primitive { + id: 0xd4bacb77 + name: "u32" + encoding: UNSIGNED_INTEGER + bytesize: 0x00000004 +} +member { + id: 0x288078fc + type_id: 0x2d2f93e0 # u8 +} +member { + id: 0x976dc47d + name: "__0" + type_id: 0xd4bacb77 # u32 + offset: 32 +} +member { + id: 0xdb2c3143 + name: "__1" + type_id: 0xd4bacb77 # u32 + offset: 64 +} +member { + id: 0xa0f58f35 + name: "x" + type_id: 0x47ea5d8b # i16 + offset: 16 +} +member { + id: 0xff34ede2 + name: "y" + type_id: 0x47ea5d8b # i16 + offset: 32 +} +member { + id: 0x2172932a + name: "z" + type_id: 0x47ea5d8b # i16 + offset: 48 +} +variant_member { + id: 0xfc632c0e + name: "Unit" + discriminant_value: 0 + type_id: 0x624786fb +} +variant_member { + id: 0xad130615 + name: "TwoU32s" + discriminant_value: 1 + type_id: 0x117f6853 +} +variant_member { + id: 0xc48d72bf + name: "ThreeI16s" + discriminant_value: 2 + type_id: 0x0e0db07a +} struct_union { - id: 0x176387ba + id: 0x0e0db07a kind: STRUCT - name: "simple::Foo" + name: "simple::Foo::ThreeI16s" + definition { + bytesize: 12 + member_id: 0xa0f58f35 # i16 x + member_id: 0xff34ede2 # i16 y + member_id: 0x2172932a # i16 z + } +} +struct_union { + id: 0x117f6853 + kind: STRUCT + name: "simple::Foo::TwoU32s" definition { bytesize: 12 + member_id: 0x976dc47d # u32 __0 + member_id: 0xdb2c3143 # u32 __1 } } +struct_union { + id: 0x624786fb + kind: STRUCT + name: "simple::Foo::Unit" + definition { + bytesize: 12 + } +} +variant { + id: 0x157ee975 + name: "simple::Foo" + bytesize: 12 + discriminant: 0x288078fc + member_id: 0xfc632c0e + member_id: 0xad130615 + member_id: 0xc48d72bf +} function { - id: 0xbb888a50 + id: 0xbb0fd1e3 return_type_id: 0x62aebfd4 # bool - parameter_id: 0x176387ba # struct simple::Foo + parameter_id: 0x157ee975 # variant simple::Foo } elf_symbol { id: 0x4e2f2fc8 name: "is_unit" is_defined: true symbol_type: FUNCTION - type_id: 0xbb888a50 # bool(struct simple::Foo) + type_id: 0xbb0fd1e3 # bool(variant simple::Foo) full_name: "simple::is_unit" } interface { id: 0x84ea5130 - symbol_id: 0x4e2f2fc8 # bool simple::is_unit(struct simple::Foo) + symbol_id: 0x4e2f2fc8 # bool simple::is_unit(variant simple::Foo) } diff --git a/test_cases/info_tests/variant/expected/singleton_rs.elf_stg b/test_cases/info_tests/variant/expected/singleton_rs.elf_stg new file mode 100644 index 0000000..ed52414 --- /dev/null +++ b/test_cases/info_tests/variant/expected/singleton_rs.elf_stg @@ -0,0 +1,42 @@ +version: 0x00000002 +root_id: 0x84ea5130 # interface +primitive { + id: 0x62aebfd4 + name: "bool" + encoding: BOOLEAN + bytesize: 0x00000001 +} +variant_member { + id: 0xfc304e1e + name: "Unit" + type_id: 0x312c753c +} +struct_union { + id: 0x312c753c + kind: STRUCT + name: "singleton::Singleton::Unit" + definition { + } +} +variant { + id: 0x9063b3ee + name: "singleton::Singleton" + member_id: 0xfc304e1e +} +function { + id: 0x9a488745 + return_type_id: 0x62aebfd4 # bool + parameter_id: 0x9063b3ee # variant singleton::Singleton +} +elf_symbol { + id: 0x4e2f2fc8 + name: "is_unit" + is_defined: true + symbol_type: FUNCTION + type_id: 0x9a488745 # bool(variant singleton::Singleton) + full_name: "singleton::is_unit" +} +interface { + id: 0x84ea5130 + symbol_id: 0x4e2f2fc8 # bool singleton::is_unit(variant singleton::Singleton) +} diff --git a/test_cases/info_tests/variant/offset_discriminant.rs b/test_cases/info_tests/variant/offset_discriminant.rs new file mode 100644 index 0000000..a7aca13 --- /dev/null +++ b/test_cases/info_tests/variant/offset_discriminant.rs @@ -0,0 +1,13 @@ +pub enum Foo { + Two(char, char), + One(char), + Zero, +} + +#[no_mangle] +pub fn is_zero(foo: Foo) -> bool { + match foo { + Foo::Zero => true, + _ => false, + } +} diff --git a/test_cases/info_tests/variant/optional_empty.rs b/test_cases/info_tests/variant/optional_empty.rs new file mode 100644 index 0000000..1cda07c --- /dev/null +++ b/test_cases/info_tests/variant/optional_empty.rs @@ -0,0 +1,9 @@ +pub enum Empty {} + +#[no_mangle] +pub fn is_none(opt: Option<Empty>) -> bool { + match opt { + None => true, + _ => false, + } +} diff --git a/test_cases/info_tests/variant/singleton.rs b/test_cases/info_tests/variant/singleton.rs new file mode 100644 index 0000000..dd66c40 --- /dev/null +++ b/test_cases/info_tests/variant/singleton.rs @@ -0,0 +1,10 @@ +pub enum Singleton { + Unit, +} + +#[no_mangle] +pub fn is_unit(s: Singleton) -> bool { + match s { + Singleton::Unit => true, + } +} diff --git a/type_normalisation.cc b/type_normalisation.cc index aeac699..292957b 100644 --- a/type_normalisation.cc +++ b/type_normalisation.cc @@ -146,7 +146,9 @@ struct FindQualifiedTypesAndFunctions { } void operator()(const Variant& x, Id) { - (*this)(x.discriminant_type_id); + if (x.discriminant.has_value()) { + (*this)(x.discriminant.value()); + } (*this)(x.members); } diff --git a/unification.cc b/unification.cc index 0d77012..21ba792 100644 --- a/unification.cc +++ b/unification.cc @@ -20,6 +20,7 @@ #include "unification.h" #include <cstddef> +#include <optional> #include <utility> #include "graph.h" @@ -79,6 +80,14 @@ struct Unifier { return true; } + bool operator()(const std::optional<Id>& opt1, + const std::optional<Id>& opt2) { + if (opt1.has_value() && opt2.has_value()) { + return (*this)(opt1.value(), opt2.value()); + } + return opt1.has_value() == opt2.has_value(); + } + bool operator()(const std::vector<Id>& ids1, const std::vector<Id>& ids2) { bool result = ids1.size() == ids2.size(); for (size_t ix = 0; result && ix < ids1.size(); ++ix) { @@ -208,7 +217,7 @@ struct Unifier { Winner operator()(const Variant& x1, const Variant& x2) { return x1.name == x2.name && x1.bytesize == x2.bytesize - && (*this)(x1.discriminant_type_id, x2.discriminant_type_id) + && (*this)(x1.discriminant, x2.discriminant) && (*this)(x1.members, x2.members) ? Right : Neither; } |