From 345f8db1c49efe3d9ca9859a296f24e728a3b43a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 18 Sep 2018 17:51:50 -0400 Subject: [PATCH] fix optional pointer to empty struct incorrectly being non-null closes #1178 --- src/analyze.cpp | 14 +++++++++++--- src/analyze.hpp | 1 + src/ir.cpp | 15 ++++++++++----- test/cases/null.zig | 6 ++++++ 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 328eda786..f37418e4f 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3971,7 +3971,7 @@ void resolve_container_type(CodeGen *g, ZigType *type_entry) { } } -ZigType *get_codegen_ptr_type(ZigType *type) { +ZigType *get_src_ptr_type(ZigType *type) { if (type->id == ZigTypeIdPointer) return type; if (type->id == ZigTypeIdFn) return type; if (type->id == ZigTypeIdPromise) return type; @@ -3983,12 +3983,19 @@ ZigType *get_codegen_ptr_type(ZigType *type) { return nullptr; } +ZigType *get_codegen_ptr_type(ZigType *type) { + ZigType *ty = get_src_ptr_type(type); + if (ty == nullptr || !type_has_bits(ty)) + return nullptr; + return ty; +} + bool type_is_codegen_pointer(ZigType *type) { return get_codegen_ptr_type(type) == type; } uint32_t get_ptr_align(CodeGen *g, ZigType *type) { - ZigType *ptr_type = get_codegen_ptr_type(type); + ZigType *ptr_type = get_src_ptr_type(type); if (ptr_type->id == ZigTypeIdPointer) { return (ptr_type->data.pointer.explicit_alignment == 0) ? get_abi_alignment(g, ptr_type->data.pointer.child_type) : ptr_type->data.pointer.explicit_alignment; @@ -3996,6 +4003,7 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) { // I tried making this use LLVMABIAlignmentOfType but it trips this assertion in LLVM: // "Cannot getTypeInfo() on a type that is unsized!" // when getting the alignment of `?extern fn() void`. + // See http://lists.llvm.org/pipermail/llvm-dev/2018-September/126142.html return (ptr_type->data.fn.fn_type_id.alignment == 0) ? 1 : ptr_type->data.fn.fn_type_id.alignment; } else if (ptr_type->id == ZigTypeIdPromise) { return get_coro_frame_align_bytes(g); @@ -4005,7 +4013,7 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) { } bool get_ptr_const(ZigType *type) { - ZigType *ptr_type = get_codegen_ptr_type(type); + ZigType *ptr_type = get_src_ptr_type(type); if (ptr_type->id == ZigTypeIdPointer) { return ptr_type->data.pointer.is_const; } else if (ptr_type->id == ZigTypeIdFn) { diff --git a/src/analyze.hpp b/src/analyze.hpp index 874a29ceb..bcc02d1a4 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -53,6 +53,7 @@ Tld *find_decl(CodeGen *g, Scope *scope, Buf *name); void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *source_node); bool type_is_codegen_pointer(ZigType *type); +ZigType *get_src_ptr_type(ZigType *type); ZigType *get_codegen_ptr_type(ZigType *type); uint32_t get_ptr_align(CodeGen *g, ZigType *type); bool get_ptr_const(ZigType *type); diff --git a/src/ir.cpp b/src/ir.cpp index 014344597..7b2ae30a7 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -155,7 +155,7 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { - assert(get_codegen_ptr_type(const_val->type) != nullptr); + assert(get_src_ptr_type(const_val->type) != nullptr); assert(const_val->special == ConstValSpecialStatic); ConstExprValue *result; switch (const_val->data.x_ptr.special) { @@ -20161,12 +20161,15 @@ static ZigType *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtr if (type_is_invalid(src_type)) return ira->codegen->builtin_types.entry_invalid; - if (get_codegen_ptr_type(src_type) == nullptr) { + // We have a check for zero bits later so we use get_src_ptr_type to + // validate src_type and dest_type. + + if (get_src_ptr_type(src_type) == nullptr) { ir_add_error(ira, ptr, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name))); return ira->codegen->builtin_types.entry_invalid; } - if (get_codegen_ptr_type(dest_type) == nullptr) { + if (get_src_ptr_type(dest_type) == nullptr) { ir_add_error(ira, dest_type_value, buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name))); return ira->codegen->builtin_types.entry_invalid; @@ -20465,7 +20468,8 @@ static ZigType *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstructionI if (type_is_invalid(dest_type)) return ira->codegen->builtin_types.entry_invalid; - if (get_codegen_ptr_type(dest_type) == nullptr) { + // We explicitly check for the size, so we can use get_src_ptr_type + if (get_src_ptr_type(dest_type) == nullptr) { ir_add_error(ira, dest_type_value, buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name))); return ira->codegen->builtin_types.entry_invalid; } @@ -20571,7 +20575,8 @@ static ZigType *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstructionP ZigType *usize = ira->codegen->builtin_types.entry_usize; - if (get_codegen_ptr_type(target->value.type) == nullptr) { + // We check size explicitly so we can use get_src_ptr_type here. + if (get_src_ptr_type(target->value.type) == nullptr) { ir_add_error(ira, target, buf_sprintf("expected pointer, found '%s'", buf_ptr(&target->value.type->name))); return ira->codegen->builtin_types.entry_invalid; diff --git a/test/cases/null.zig b/test/cases/null.zig index c86dd34b0..89cef495a 100644 --- a/test/cases/null.zig +++ b/test/cases/null.zig @@ -154,3 +154,9 @@ test "optional types" { const StructWithOptionalType = struct { t: ?type, }; + +test "optional pointer to 0 bit type null value at runtime" { + const EmptyStruct = struct {}; + var x: ?*EmptyStruct = null; + assert(x == null); +}