Commit c96d565166

Andrew Kelley <andrew@ziglang.org>
2019-11-24 23:02:56
add compile error for incompatible pointer sentinels
1 parent 4018034
Changed files (2)
src/ir.cpp
@@ -183,6 +183,7 @@ struct ConstCastBadCV {
 
 struct ConstCastPtrSentinel {
     ZigType *wanted_type;
+    ZigType *actual_type;
 };
 
 static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);
@@ -9898,7 +9899,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
         if (!ok_null_term_ptrs) {
             result.id = ConstCastResultIdPtrSentinel;
             result.data.bad_ptr_sentinel = allocate_nonzero<ConstCastPtrSentinel>(1);
-            result.data.bad_ptr_sentinel->wanted_type = wanted_type;
+            result.data.bad_ptr_sentinel->wanted_type = wanted_ptr_type;
+            result.data.bad_ptr_sentinel->actual_type = actual_ptr_type;
             return result;
         }
         bool ptr_lens_equal = actual_ptr_type->data.pointer.ptr_len == wanted_ptr_type->data.pointer.ptr_len;
@@ -12653,19 +12655,27 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa
             break;
         }
         case ConstCastResultIdPtrSentinel: {
+            ZigType *actual_type = cast_result->data.bad_ptr_sentinel->actual_type;
             ZigType *wanted_type = cast_result->data.bad_ptr_sentinel->wanted_type;
-            Buf *msg = buf_sprintf("destination pointer requires a terminating '");
-            render_const_value(ira->codegen, msg, wanted_type->data.pointer.sentinel);
-            buf_appendf(msg, "' sentinel value");
-            add_error_note(ira->codegen, parent_msg, source_node, msg);
+            {
+                Buf *txt_msg = buf_sprintf("destination pointer requires a terminating '");
+                render_const_value(ira->codegen, txt_msg, wanted_type->data.pointer.sentinel);
+                buf_appendf(txt_msg, "' sentinel value");
+                if (actual_type->data.pointer.sentinel != nullptr) {
+                    buf_appendf(txt_msg, ", but source pointer has a terminating '");
+                    render_const_value(ira->codegen, txt_msg, actual_type->data.pointer.sentinel);
+                    buf_appendf(txt_msg, "' sentinel value");
+                }
+                add_error_note(ira->codegen, parent_msg, source_node, txt_msg);
+            }
             break;
         }
         case ConstCastResultIdSentinelArrays: {
             ZigType *wanted_type = cast_result->data.sentinel_arrays->wanted_type;
-            Buf *msg = buf_sprintf("destination array requires a terminating '");
-            render_const_value(ira->codegen, msg, wanted_type->data.pointer.sentinel);
-            buf_appendf(msg, "' sentinel value");
-            add_error_note(ira->codegen, parent_msg, source_node, msg);
+            Buf *txt_msg = buf_sprintf("destination array requires a terminating '");
+            render_const_value(ira->codegen, txt_msg, wanted_type->data.pointer.sentinel);
+            buf_appendf(txt_msg, "' sentinel value");
+            add_error_note(ira->codegen, parent_msg, source_node, txt_msg);
             break;
         }
         case ConstCastResultIdCV: {
test/compile_errors.zig
@@ -2,6 +2,21 @@ const tests = @import("tests.zig");
 const builtin = @import("builtin");
 
 pub fn addCases(cases: *tests.CompileErrorContext) void {
+    cases.add(
+        "incompatible pointer sentinels",
+        \\export fn entry1(ptr: [*:255]u8) [*:0]u8 {
+        \\    return ptr;
+        \\}
+        \\export fn entry2(ptr: [*]u8) [*:0]u8 {
+        \\    return ptr;
+        \\}
+    ,
+        "tmp.zig:2:5: error: expected type '[*:0]u8', found '[*:255]u8'",
+        "tmp.zig:2:5: note: destination pointer requires a terminating '0' sentinel value, but source pointer has a terminating '255' sentinel value",
+        "tmp.zig:5:5: error: expected type '[*:0]u8', found '[*]u8'",
+        "tmp.zig:5:5: note: destination pointer requires a terminating '0' sentinel value",
+    );
+
     cases.add(
         "regression test #2980: base type u32 is not type checked properly when assigning a value within a struct",
         \\const Foo = struct {