Commit 259413251d

Andrew Kelley <superjoe30@gmail.com>
2018-06-12 21:06:02
fix ability to call mutating methods on zero size structs
closes #838
1 parent 7580e39
Changed files (2)
src
test
src/ir.cpp
@@ -8151,6 +8151,17 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
         }
     }
 
+    // implicit T to *T where T is zero bits
+    if (expected_type->id == TypeTableEntryIdPointer && expected_type->data.pointer.ptr_len == PtrLenSingle &&
+        types_match_const_cast_only(ira, expected_type->data.pointer.child_type,
+            actual_type, source_node).id == ConstCastResultIdOk)
+    {
+        type_ensure_zero_bits_known(ira->codegen, actual_type);
+        if (!type_has_bits(actual_type)) {
+            return ImplicitCastMatchResultYes;
+        }
+    }
+
     // implicit undefined literal to anything
     if (actual_type->id == TypeTableEntryIdUndefined) {
         return ImplicitCastMatchResultYes;
@@ -8820,7 +8831,7 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
 static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
         TypeTableEntry *wanted_type, CastOp cast_op, bool need_alloca)
 {
-    if (value->value.special != ConstValSpecialRuntime &&
+    if ((instr_is_comptime(value) || !type_has_bits(wanted_type)) &&
         cast_op != CastOpResizeSlice && cast_op != CastOpBytesToSlice)
     {
         IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
@@ -9382,9 +9393,19 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
 
     if (value->id == IrInstructionIdLoadPtr) {
         IrInstructionLoadPtr *load_ptr_inst = (IrInstructionLoadPtr *) value;
+
         if (load_ptr_inst->ptr->value.type->data.pointer.is_const) {
             return load_ptr_inst->ptr;
         }
+
+        type_ensure_zero_bits_known(ira->codegen, value->value.type);
+        if (type_is_invalid(value->value.type)) {
+            return ira->codegen->invalid_instruction;
+        }
+
+        if (!type_has_bits(value->value.type)) {
+            return load_ptr_inst->ptr;
+        }
     }
 
     if (instr_is_comptime(value)) {
@@ -10340,6 +10361,20 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
         }
     }
 
+    // explicit cast from T to *T where T is zero bits
+    if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
+        types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
+            actual_type, source_node).id == ConstCastResultIdOk)
+    {
+        type_ensure_zero_bits_known(ira->codegen, actual_type);
+        if (type_is_invalid(actual_type)) {
+            return ira->codegen->invalid_instruction;
+        }
+        if (!type_has_bits(actual_type)) {
+            return ir_get_ref(ira, source_instr, value, false, false);
+        }
+    }
+
 
     // explicit cast from undefined to anything
     if (actual_type->id == TypeTableEntryIdUndefined) {
test/cases/struct.zig
@@ -421,3 +421,20 @@ const Expr = union(enum) {
 fn alloc(comptime T: type) []T {
     return []T{};
 }
+
+test "call method with mutable reference to struct with no fields" {
+    const S = struct {
+        fn doC(s: *const this) bool {
+            return true;
+        }
+        fn do(s: *this) bool {
+            return true;
+        }
+    };
+
+    var s = S{};
+    assert(S.doC(&s));
+    assert(s.doC());
+    assert(S.do(&s));
+    assert(s.do());
+}