aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--comparison.cc12
-rw-r--r--dwarf_processor.cc102
-rw-r--r--equality.h11
-rw-r--r--fingerprint.cc5
-rw-r--r--graph.h8
-rw-r--r--proto_reader.cc7
-rw-r--r--proto_writer.cc4
-rw-r--r--stable_hash.cc4
-rw-r--r--stg.proto2
-rw-r--r--substitution.h4
-rw-r--r--test_cases/info_tests/variant/expected/negative_discriminant_rs.elf_stg79
-rw-r--r--test_cases/info_tests/variant/expected/offset_discriminant_rs.elf_stg106
-rw-r--r--test_cases/info_tests/variant/expected/optional_empty_rs.elf_stg65
-rw-r--r--test_cases/info_tests/variant/expected/simple_rs.elf_stg112
-rw-r--r--test_cases/info_tests/variant/expected/singleton_rs.elf_stg42
-rw-r--r--test_cases/info_tests/variant/offset_discriminant.rs13
-rw-r--r--test_cases/info_tests/variant/optional_empty.rs9
-rw-r--r--test_cases/info_tests/variant/singleton.rs10
-rw-r--r--type_normalisation.cc4
-rw-r--r--unification.cc11
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);
diff --git a/equality.h b/equality.h
index eb47db9..6f96bc1 100644
--- a/equality.h
+++ b/equality.h
@@ -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;
}
diff --git a/graph.h b/graph.h
index f75173a..0955675 100644
--- a/graph.h
+++ b/graph.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));
}
diff --git a/stg.proto b/stg.proto
index 7703b79..5ba2d6c 100644
--- a/stg.proto
+++ b/stg.proto
@@ -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;
}