Commit 129ccad434

LemonBoy <thatlemon@gmail.com>
2020-11-07 23:45:54
stage1: Reject undefined values when taking union ptr
The code rightfully assumes the union_val object to be fully initialized. Closes #7019
1 parent 252924a
Changed files (2)
src
stage1
test
src/stage1/ir.cpp
@@ -22713,6 +22713,16 @@ static IrInstGen *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name
                 if (type_is_invalid(union_val->type))
                     return ira->codegen->invalid_inst_gen;
 
+                // Reject undefined values unless we're intializing the union:
+                // a undefined union means also the tag is undefined, accessing
+                // its payload slot is UB.
+                const UndefAllowed allow_undef = initializing ? UndefOk : UndefBad;
+                if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec,
+                                source_instr->source_node, union_val, allow_undef)))
+                {
+                    return ira->codegen->invalid_inst_gen;
+                }
+
                 if (initializing) {
                     ZigValue *payload_val = ira->codegen->pass1_arena->create<ZigValue>();
                     payload_val->special = ConstValSpecialUndef;
@@ -22737,6 +22747,7 @@ static IrInstGen *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name
                 }
 
                 ZigValue *payload_val = union_val->data.x_union.payload;
+                assert(payload_val);
 
                 IrInstGen *result;
                 if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
test/compile_errors.zig
@@ -11,6 +11,21 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         "tmp.zig:1:50: error: use of undefined value here causes undefined behavior",
     });
 
+    cases.add("wrong initializer for union payload of type 'type'",
+        \\const U = union(enum) {
+        \\    A: type,
+        \\};
+        \\const S = struct {
+        \\    u: U,
+        \\};
+        \\export fn entry() void {
+        \\    comptime var v: S = undefined;
+        \\    v.u.A = U{ .A = i32 };
+        \\}
+    , &[_][]const u8{
+        "tmp.zig:9:8: error: use of undefined value here causes undefined behavior",
+    });
+
     cases.add("union with too small explicit signed tag type",
         \\const U = union(enum(i2)) {
         \\    A: u8,