commit d4bd9749de1ea29690b9f9d4d9c6a04c69da05bc
parent 1ee3a9573c990bc15544be8cbcb7ca2879c439cb
Author: Drew DeVault <sir@cmpwn.com>
Date: Thu, 5 Aug 2021 15:44:56 +0200
gen: implement subtype tagged casts
Just one of two cases is implemented here; the second requires more
work.
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
2 files changed, 38 insertions(+), 6 deletions(-)
diff --git a/src/gen.c b/src/gen.c
@@ -124,7 +124,9 @@ gen_store(struct gen_context *ctx,
gen_copy_aligned(ctx, object, value);
return;
case STORAGE_TAGGED:
- assert(0); // TODO
+ // TODO: We can be smarter in this case
+ gen_copy_aligned(ctx, object, value);
+ return;
case STORAGE_UNION:
gen_copy_memcpy(ctx, object, value);
return;
@@ -463,10 +465,23 @@ gen_expr_cast_at(struct gen_context *ctx,
return;
}
- // Cast to tagged union
const struct type *subtype = tagged_select_subtype(to, from);
- assert(subtype); // TODO: Casting between incompatible tagged unions
+ assert(subtype || tagged_subset_compat(to, from));
+ if (!subtype && to->align == from->align) {
+ // Case 1: from is a union whose members are a subset of to, and
+ // the alignment matches, so we can just interpret values of
+ // type 'from' as if it were of type 'to'
+ struct gen_value out2 = out;
+ out2.type = from;
+ gen_expr_at(ctx, expr->cast.value, out2);
+ return;
+ } else if (!subtype) {
+ // Case 2: alignment mismatch, so (much) more work is required.
+ assert(0); // TODO
+ return;
+ }
+ // Case 3: from is a member of to
struct qbe_value qout = mkqval(ctx, &out);
struct qbe_value id = constw(subtype->id);
enum qbe_instr store = store_for_type(ctx, &builtin_type_uint);
diff --git a/tests/910-tagged.ha b/tests/910-tagged.ha
@@ -1,4 +1,4 @@
-fn totagged() void = {
+fn membercast() void = {
// Simple case
let x: (int | void) = void;
let p = &x: *struct {
@@ -33,11 +33,28 @@ fn totagged() void = {
};
assert(p.id == 4119164483);
assert(p.data == 1337z);
+};
+
+fn subsetcast() void = {
+ // Equal alignment
+ let x: (size | void) = 1337z;
+ let y: (size | int | void) = x;
+ let p = &y: *struct {
+ tag: uint,
+ data: union {
+ z: size,
+ i: int,
+ },
+ };
+ assert(p.tag == 4119164483);
+ assert(p.data.z == 1337z);
- // TODO: More cases
+ // Disjoint alignment
+ // TODO
};
export fn main() int = {
- totagged();
+ membercast();
+ subsetcast();
return 0;
};