diff --git a/doc/langref.html.in b/doc/langref.html.in index 24b976ee42..491e7f8f6c 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -10405,7 +10405,7 @@ pub fn main() !void {

String literals such as {#syntax#}"foo"{#endsyntax#} are in the global constant data section. This is why it is an error to pass a string literal to a mutable slice, like this:

- {#code_begin|test_err|expected type '[]u8'#} + {#code_begin|test_err|cannot cast pointer to array literal to slice type '[]u8'#} fn foo(s: []u8) void { _ = s; } diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index 63466849a4..3ac1ddb51c 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -7843,7 +7843,7 @@ static Stage1AirInst *ir_analyze_cast(IrAnalyze *ira, Scope *scope, AstNode *sou bool const_ok = (slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 || !actual_type->data.pointer.is_const); - if (const_ok && types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type, + if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type, array_type->data.array.child_type, source_node, !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk && (slice_ptr_type->data.pointer.sentinel == nullptr || @@ -7851,6 +7851,14 @@ static Stage1AirInst *ir_analyze_cast(IrAnalyze *ira, Scope *scope, AstNode *sou const_values_equal(ira->codegen, array_type->data.array.sentinel, slice_ptr_type->data.pointer.sentinel)))) { + if (!const_ok) { + ErrorMsg *msg = ir_add_error_node(ira, source_node, + buf_sprintf("cannot cast pointer to array literal to slice type '%s'", + buf_ptr(&wanted_type->name))); + add_error_note(ira->codegen, msg, source_node, + buf_sprintf("cast discards const qualifier")); + return ira->codegen->invalid_inst_gen; + } // If the pointers both have ABI align, it works. // Or if the array length is 0, alignment doesn't matter. bool ok_align = array_type->data.array.len == 0 || @@ -8208,8 +8216,16 @@ static Stage1AirInst *ir_analyze_cast(IrAnalyze *ira, Scope *scope, AstNode *sou ZigType *wanted_child = wanted_type->data.pointer.child_type; bool const_ok = (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const); if (wanted_child->id == ZigTypeIdArray && (is_array_init || field_count == 0) && - wanted_child->data.array.len == field_count && (const_ok || field_count == 0)) + wanted_child->data.array.len == field_count) { + if (!const_ok && field_count != 0) { + ErrorMsg *msg = ir_add_error_node(ira, source_node, + buf_sprintf("cannot cast pointer to array literal to '%s'", + buf_ptr(&wanted_type->name))); + add_error_note(ira->codegen, msg, source_node, + buf_sprintf("cast discards const qualifier")); + return ira->codegen->invalid_inst_gen; + } Stage1AirInst *res = ir_analyze_struct_literal_to_array(ira, scope, source_node, value, anon_type, wanted_child); if (res->value->type->id == ZigTypeIdPointer) return res; @@ -8241,6 +8257,13 @@ static Stage1AirInst *ir_analyze_cast(IrAnalyze *ira, Scope *scope, AstNode *sou res = ir_get_ref(ira, scope, source_node, res, actual_type->data.pointer.is_const, actual_type->data.pointer.is_volatile); return ir_resolve_ptr_of_array_to_slice(ira, scope, source_node, res, wanted_type, nullptr); + } else if (!slice_type->data.pointer.is_const && actual_type->data.pointer.is_const && field_count != 0) { + ErrorMsg *msg = ir_add_error_node(ira, source_node, + buf_sprintf("cannot cast pointer to array literal to slice type '%s'", + buf_ptr(&wanted_type->name))); + add_error_note(ira->codegen, msg, source_node, + buf_sprintf("cast discards const qualifier")); + return ira->codegen->invalid_inst_gen; } } } @@ -15068,7 +15091,7 @@ static Stage1AirInst *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, Stage1ZirI return ira->codegen->invalid_inst_gen; if (actual_array_type->id != ZigTypeIdArray) { ir_add_error_node(ira, elem_ptr_instruction->init_array_type_source_node, - buf_sprintf("array literal requires address-of operator to coerce to slice type '%s'", + buf_sprintf("array literal requires address-of operator (&) to coerce to slice type '%s'", buf_ptr(&actual_array_type->name))); return ira->codegen->invalid_inst_gen; } @@ -17473,7 +17496,7 @@ static Stage1AirInst *ir_analyze_instruction_container_init_list(IrAnalyze *ira, if (is_slice(container_type)) { ir_add_error_node(ira, instruction->init_array_type_source_node, - buf_sprintf("array literal requires address-of operator to coerce to slice type '%s'", + buf_sprintf("array literal requires address-of operator (&) to coerce to slice type '%s'", buf_ptr(&container_type->name))); return ira->codegen->invalid_inst_gen; } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index faed747a61..967ec1e9ec 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -86,9 +86,12 @@ pub fn addCases(ctx: *TestContext) !void { \\ _ = c; \\} , &[_][]const u8{ - "tmp.zig:2:31: error: expected type '[][]const u8', found '*const struct:2:31'", - "tmp.zig:6:33: error: expected type '*[2][]const u8', found '*const struct:6:33'", + "tmp.zig:2:31: error: cannot cast pointer to array literal to slice type '[][]const u8'", + "tmp.zig:2:31: note: cast discards const qualifier", + "tmp.zig:6:33: error: cannot cast pointer to array literal to '*[2][]const u8'", + "tmp.zig:6:33: note: cast discards const qualifier", "tmp.zig:11:21: error: expected type '*S', found '*const struct:11:21'", + "tmp.zig:11:21: note: cast discards const qualifier", }); ctx.objErrStage1("@Type() union payload is undefined", @@ -1962,7 +1965,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ _ = geo_data; \\} , &[_][]const u8{ - "tmp.zig:4:30: error: array literal requires address-of operator to coerce to slice type '[][2]f32'", + "tmp.zig:4:30: error: array literal requires address-of operator (&) to coerce to slice type '[][2]f32'", }); ctx.objErrStage1("slicing of global undefined pointer", @@ -2537,7 +2540,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ _ = x; \\} , &[_][]const u8{ - "tmp.zig:2:15: error: array literal requires address-of operator to coerce to slice type '[]u8'", + "tmp.zig:2:15: error: array literal requires address-of operator (&) to coerce to slice type '[]u8'", }); ctx.objErrStage1("slice passed as array init type", @@ -2546,7 +2549,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ _ = x; \\} , &[_][]const u8{ - "tmp.zig:2:15: error: array literal requires address-of operator to coerce to slice type '[]u8'", + "tmp.zig:2:15: error: array literal requires address-of operator (&) to coerce to slice type '[]u8'", }); ctx.objErrStage1("inferred array size invalid here", @@ -3493,7 +3496,8 @@ pub fn addCases(ctx: *TestContext) !void { \\ _ = sliceA; \\} , &[_][]const u8{ - "tmp.zig:3:27: error: expected type '[]u8', found '*const [1]u8'", + "tmp.zig:3:27: error: cannot cast pointer to array literal to slice type '[]u8'", + "tmp.zig:3:27: note: cast discards const qualifier", }); ctx.objErrStage1("deref slice and get len field", @@ -8717,7 +8721,8 @@ pub fn addCases(ctx: *TestContext) !void { \\ comptime ignore(@typeInfo(MyStruct).Struct.fields[0]); \\} , &[_][]const u8{ - ":5:28: error: expected type '[]u8', found '*const [3:0]u8'", + ":5:28: error: cannot cast pointer to array literal to slice type '[]u8'", + ":5:28: note: cast discards const qualifier", }); ctx.objErrStage1("integer underflow error",