authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-04-10 18:26:45+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-04-10 18:26:45+03:00
log732c0cb58c842279404a8b1acad0f18b6650ea66
treed7a7436aa669dcd8abada1a6097ef0ca7e652f97
parent4871345545ec9655a14d0bfe32668eda210953f7
parentf60e7348d58c3f3e3d9fe50ab5666287a77b00e7
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #4985 from Vexu/assignment-error

Add missing error message for invalid assignment

4 files changed, 136 insertions(+), 28 deletions(-)

src/all_types.hpp+1
......@@ -2406,6 +2406,7 @@ struct ScopeDecls {
24062406enum LVal {
24072407 LValNone,
24082408 LValPtr,
2409 LValAssign,
24092410};
24102411
24112412// This scope comes from a block expression in user code.
src/ir.cpp+113-16
......@@ -5527,7 +5527,7 @@ static IrInstSrc *ir_gen_merge_err_sets(IrBuilderSrc *irb, Scope *scope, AstNode
55275527}
55285528
55295529static IrInstSrc *ir_gen_assign(IrBuilderSrc *irb, Scope *scope, AstNode *node) {
5530 IrInstSrc *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPtr, nullptr);
5530 IrInstSrc *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValAssign, nullptr);
55315531 if (lvalue == irb->codegen->invalid_inst_src)
55325532 return irb->codegen->invalid_inst_src;
55335533
......@@ -5546,7 +5546,7 @@ static IrInstSrc *ir_gen_assign(IrBuilderSrc *irb, Scope *scope, AstNode *node)
55465546}
55475547
55485548static IrInstSrc *ir_gen_assign_merge_err_sets(IrBuilderSrc *irb, Scope *scope, AstNode *node) {
5549 IrInstSrc *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPtr, nullptr);
5549 IrInstSrc *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValAssign, nullptr);
55505550 if (lvalue == irb->codegen->invalid_inst_src)
55515551 return lvalue;
55525552 IrInstSrc *op1 = ir_build_load_ptr(irb, scope, node->data.bin_op_expr.op1, lvalue);
......@@ -5559,7 +5559,7 @@ static IrInstSrc *ir_gen_assign_merge_err_sets(IrBuilderSrc *irb, Scope *scope,
55595559}
55605560
55615561static IrInstSrc *ir_gen_assign_op(IrBuilderSrc *irb, Scope *scope, AstNode *node, IrBinOp op_id) {
5562 IrInstSrc *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPtr, nullptr);
5562 IrInstSrc *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValAssign, nullptr);
55635563 if (lvalue == irb->codegen->invalid_inst_src)
55645564 return lvalue;
55655565 IrInstSrc *op1 = ir_build_load_ptr(irb, scope, node->data.bin_op_expr.op1, lvalue);
......@@ -5908,7 +5908,7 @@ static IrInstSrc *ir_gen_symbol(IrBuilderSrc *irb, Scope *scope, AstNode *node,
59085908 Buf *variable_name = node->data.symbol_expr.symbol;
59095909
59105910 if (buf_eql_str(variable_name, "_")) {
5911 if (lval == LValPtr) {
5911 if (lval == LValAssign) {
59125912 IrInstSrcConst *const_instruction = ir_build_instruction<IrInstSrcConst>(irb, scope, node);
59135913 const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
59145914 const_instruction->value->type = get_pointer_to_type(irb->codegen,
......@@ -5933,7 +5933,7 @@ static IrInstSrc *ir_gen_symbol(IrBuilderSrc *irb, Scope *scope, AstNode *node,
59335933 assert(err == ErrorPrimitiveTypeNotFound);
59345934 } else {
59355935 IrInstSrc *value = ir_build_const_type(irb, scope, node, primitive_type);
5936 if (lval == LValPtr) {
5936 if (lval == LValPtr || lval == LValAssign) {
59375937 return ir_build_ref_src(irb, scope, node, value);
59385938 } else {
59395939 return ir_expr_wrap(irb, scope, value, result_loc);
......@@ -5944,7 +5944,7 @@ static IrInstSrc *ir_gen_symbol(IrBuilderSrc *irb, Scope *scope, AstNode *node,
59445944 ZigVar *var = find_variable(irb->codegen, scope, variable_name, &crossed_fndef_scope);
59455945 if (var) {
59465946 IrInstSrc *var_ptr = ir_build_var_ptr_x(irb, scope, node, var, crossed_fndef_scope);
5947 if (lval == LValPtr) {
5947 if (lval == LValPtr || lval == LValAssign) {
59485948 return var_ptr;
59495949 } else {
59505950 return ir_expr_wrap(irb, scope, ir_build_load_ptr(irb, scope, node, var_ptr), result_loc);
......@@ -5954,7 +5954,7 @@ static IrInstSrc *ir_gen_symbol(IrBuilderSrc *irb, Scope *scope, AstNode *node,
59545954 Tld *tld = find_decl(irb->codegen, scope, variable_name);
59555955 if (tld) {
59565956 IrInstSrc *decl_ref = ir_build_decl_ref(irb, scope, node, tld, lval);
5957 if (lval == LValPtr) {
5957 if (lval == LValPtr || lval == LValAssign) {
59585958 return decl_ref;
59595959 } else {
59605960 return ir_expr_wrap(irb, scope, decl_ref, result_loc);
......@@ -5995,7 +5995,7 @@ static IrInstSrc *ir_gen_array_access(IrBuilderSrc *irb, Scope *scope, AstNode *
59955995
59965996 IrInstSrc *ptr_instruction = ir_build_elem_ptr(irb, scope, node, array_ref_instruction,
59975997 subscript_instruction, true, PtrLenSingle, nullptr);
5998 if (lval == LValPtr)
5998 if (lval == LValPtr || lval == LValAssign)
59995999 return ptr_instruction;
60006000
60016001 IrInstSrc *load_ptr = ir_build_load_ptr(irb, scope, node, ptr_instruction);
......@@ -6754,7 +6754,7 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod
67546754 IrInstSrc *ptr_instruction = ir_build_field_ptr_instruction(irb, scope, node,
67556755 arg0_value, arg1_value, false);
67566756
6757 if (lval == LValPtr)
6757 if (lval == LValPtr || lval == LValAssign)
67586758 return ptr_instruction;
67596759
67606760 IrInstSrc *load_ptr = ir_build_load_ptr(irb, scope, node, ptr_instruction);
......@@ -7479,6 +7479,7 @@ static IrInstSrc *ir_lval_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *value
74797479 return value;
74807480 }
74817481
7482 assert(lval != LValAssign);
74827483 if (lval == LValPtr) {
74837484 // We needed a pointer to a value, but we got a value. So we create
74847485 // an instruction which just makes a pointer of it.
......@@ -9962,7 +9963,7 @@ static IrInstSrc *ir_gen_node_raw(IrBuilderSrc *irb, AstNode *node, Scope *scope
99629963 IrInstSrc *ptr_instruction = ir_gen_field_access(irb, scope, node);
99639964 if (ptr_instruction == irb->codegen->invalid_inst_src)
99649965 return ptr_instruction;
9965 if (lval == LValPtr)
9966 if (lval == LValPtr || lval == LValAssign)
99669967 return ptr_instruction;
99679968
99689969 IrInstSrc *load_ptr = ir_build_load_ptr(irb, scope, node, ptr_instruction);
......@@ -9970,7 +9971,12 @@ static IrInstSrc *ir_gen_node_raw(IrBuilderSrc *irb, AstNode *node, Scope *scope
99709971 }
99719972 case NodeTypePtrDeref: {
99729973 AstNode *expr_node = node->data.ptr_deref_expr.target;
9973 IrInstSrc *value = ir_gen_node_extra(irb, expr_node, scope, lval, nullptr);
9974
9975 LVal child_lval = lval;
9976 if (child_lval == LValAssign)
9977 child_lval = LValPtr;
9978
9979 IrInstSrc *value = ir_gen_node_extra(irb, expr_node, scope, child_lval, nullptr);
99749980 if (value == irb->codegen->invalid_inst_src)
99759981 return value;
99769982
......@@ -9988,7 +9994,7 @@ static IrInstSrc *ir_gen_node_raw(IrBuilderSrc *irb, AstNode *node, Scope *scope
99889994 return irb->codegen->invalid_inst_src;
99899995
99909996 IrInstSrc *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, maybe_ptr, true, false);
9991 if (lval == LValPtr)
9997 if (lval == LValPtr || lval == LValAssign)
99929998 return unwrapped_ptr;
99939999
999410000 IrInstSrc *load_ptr = ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
......@@ -10068,6 +10074,97 @@ static ResultLoc *no_result_loc(void) {
1006810074static IrInstSrc *ir_gen_node_extra(IrBuilderSrc *irb, AstNode *node, Scope *scope, LVal lval,
1006910075 ResultLoc *result_loc)
1007010076{
10077 if (lval == LValAssign) {
10078 switch (node->type) {
10079 case NodeTypeStructValueField:
10080 case NodeTypeParamDecl:
10081 case NodeTypeUsingNamespace:
10082 case NodeTypeSwitchProng:
10083 case NodeTypeSwitchRange:
10084 case NodeTypeStructField:
10085 case NodeTypeErrorSetField:
10086 case NodeTypeFnDef:
10087 case NodeTypeTestDecl:
10088 zig_unreachable();
10089
10090 // cannot be assigned to
10091 case NodeTypeBlock:
10092 case NodeTypeGroupedExpr:
10093 case NodeTypeBinOpExpr:
10094 case NodeTypeIntLiteral:
10095 case NodeTypeFloatLiteral:
10096 case NodeTypeCharLiteral:
10097 case NodeTypeIfBoolExpr:
10098 case NodeTypeContainerInitExpr:
10099 case NodeTypeVariableDeclaration:
10100 case NodeTypeWhileExpr:
10101 case NodeTypeForExpr:
10102 case NodeTypeReturnExpr:
10103 case NodeTypeBoolLiteral:
10104 case NodeTypeArrayType:
10105 case NodeTypePointerType:
10106 case NodeTypeAnyFrameType:
10107 case NodeTypeStringLiteral:
10108 case NodeTypeUndefinedLiteral:
10109 case NodeTypeAsmExpr:
10110 case NodeTypeNullLiteral:
10111 case NodeTypeIfErrorExpr:
10112 case NodeTypeIfOptional:
10113 case NodeTypeSwitchExpr:
10114 case NodeTypeCompTime:
10115 case NodeTypeNoAsync:
10116 case NodeTypeErrorType:
10117 case NodeTypeBreak:
10118 case NodeTypeContinue:
10119 case NodeTypeUnreachable:
10120 case NodeTypeDefer:
10121 case NodeTypeSliceExpr:
10122 case NodeTypeCatchExpr:
10123 case NodeTypeContainerDecl:
10124 case NodeTypeFnProto:
10125 case NodeTypeErrorSetDecl:
10126 case NodeTypeResume:
10127 case NodeTypeAwaitExpr:
10128 case NodeTypeSuspend:
10129 case NodeTypeEnumLiteral:
10130 case NodeTypeInferredArrayType:
10131 case NodeTypeVarFieldType:
10132 case NodeTypePrefixOpExpr:
10133 add_node_error(irb->codegen, node,
10134 buf_sprintf("invalid left-hand side to assignment"));
10135 return irb->codegen->invalid_inst_src;
10136
10137 // @field can be assigned to
10138 case NodeTypeFnCallExpr:
10139 if (node->data.fn_call_expr.modifier == CallModifierBuiltin) {
10140 AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
10141 Buf *name = fn_ref_expr->data.symbol_expr.symbol;
10142 auto entry = irb->codegen->builtin_fn_table.maybe_get(name);
10143
10144 if (!entry) {
10145 add_node_error(irb->codegen, node,
10146 buf_sprintf("invalid builtin function: '%s'", buf_ptr(name)));
10147 return irb->codegen->invalid_inst_src;
10148 }
10149
10150 if (entry->value->id == BuiltinFnIdField) {
10151 break;
10152 }
10153 }
10154 add_node_error(irb->codegen, node,
10155 buf_sprintf("invalid left-hand side to assignment"));
10156 return irb->codegen->invalid_inst_src;
10157
10158
10159 // can be assigned to
10160 case NodeTypeUnwrapOptional:
10161 case NodeTypePtrDeref:
10162 case NodeTypeFieldAccessExpr:
10163 case NodeTypeArrayAccessExpr:
10164 case NodeTypeSymbol:
10165 break;
10166 }
10167 }
1007110168 if (result_loc == nullptr) {
1007210169 // Create a result location indicating there is none - but if one gets created
1007310170 // it will be properly distributed.
......@@ -20581,7 +20678,7 @@ static IrInstGen *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstSrcUnOp *in
2058120678 return ira->codegen->invalid_inst_gen;
2058220679
2058320680 // If the result needs to be an lvalue, type check it
20584 if (instruction->lval == LValPtr && result->value->type->id != ZigTypeIdPointer) {
20681 if (instruction->lval != LValNone && result->value->type->id != ZigTypeIdPointer) {
2058520682 ir_add_error(ira, &instruction->base.base,
2058620683 buf_sprintf("attempt to dereference non-pointer type '%s'", buf_ptr(&result->value->type->name)));
2058720684 return ira->codegen->invalid_inst_gen;
......@@ -21175,7 +21272,7 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP
2117521272 nullptr, nullptr);
2117621273 } else if (return_type->data.pointer.explicit_alignment != 0) {
2117721274 uint32_t chosen_align;
21178 if ((err = compute_elem_align(ira, return_type->data.pointer.child_type,
21275 if ((err = compute_elem_align(ira, return_type->data.pointer.child_type,
2117921276 return_type->data.pointer.explicit_alignment, index, &chosen_align)))
2118021277 {
2118121278 return ira->codegen->invalid_inst_gen;
......@@ -23348,7 +23445,7 @@ static IrInstGen *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstSrcRef *ref_i
2334823445 IrInstGen *value = ref_instruction->value->child;
2334923446 if (type_is_invalid(value->value->type))
2335023447 return ira->codegen->invalid_inst_gen;
23351
23448
2335223449 bool is_const = false;
2335323450 bool is_volatile = false;
2335423451
......@@ -28878,7 +28975,7 @@ static IrInstGen *ir_analyze_instruction_decl_ref(IrAnalyze *ira, IrInstSrcDeclR
2887828975 return ira->codegen->invalid_inst_gen;
2887928976 }
2888028977
28881 if (instruction->lval == LValPtr) {
28978 if (instruction->lval == LValPtr || instruction->lval == LValAssign) {
2888228979 return ref_instruction;
2888328980 } else {
2888428981 return ir_get_deref(ira, &instruction->base.base, ref_instruction, nullptr);
src/ir_print.cpp+1-1
......@@ -2175,7 +2175,7 @@ static void ir_print_ptr_type(IrPrintSrc *irp, IrInstSrcPtrType *instruction) {
21752175}
21762176
21772177static void ir_print_decl_ref(IrPrintSrc *irp, IrInstSrcDeclRef *instruction) {
2178 const char *ptr_str = (instruction->lval == LValPtr) ? "ptr " : "";
2178 const char *ptr_str = (instruction->lval != LValNone) ? "ptr " : "";
21792179 fprintf(irp->f, "declref %s%s", ptr_str, buf_ptr(instruction->tld->name));
21802180}
21812181
test/compile_errors.zig+21-11
......@@ -2,6 +2,24 @@ const tests = @import("tests.zig");
22const std = @import("std");
33
44pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.addTest("invalid assignments",
6 \\export fn entry1() void {
7 \\ var a: []const u8 = "foo";
8 \\ a[0..2] = "bar";
9 \\}
10 \\export fn entry2() void {
11 \\ var a: u8 = 2;
12 \\ a + 2 = 3;
13 \\}
14 \\export fn entry4() void {
15 \\ 2 + 2 = 3;
16 \\}
17 , &[_][]const u8{
18 "tmp.zig:3:6: error: invalid left-hand side to assignment",
19 "tmp.zig:7:7: error: invalid left-hand side to assignment",
20 "tmp.zig:10:7: error: invalid left-hand side to assignment",
21 });
22
523 cases.addTest("reassign to array parameter",
624 \\fn reassign(a: [3]f32) void {
725 \\ a = [3]f32{4, 5, 6};
......@@ -10,7 +28,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1028 \\ reassign(.{1, 2, 3});
1129 \\}
1230 , &[_][]const u8{
13 "tmp.zig:2:15: error: cannot assign to constant"
31 "tmp.zig:2:15: error: cannot assign to constant",
1432 });
1533
1634 cases.addTest("reassign to slice parameter",
......@@ -21,7 +39,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2139 \\ reassign("foo");
2240 \\}
2341 , &[_][]const u8{
24 "tmp.zig:2:10: error: cannot assign to constant"
42 "tmp.zig:2:10: error: cannot assign to constant",
2543 });
2644
2745 cases.addTest("reassign to struct parameter",
......@@ -35,7 +53,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3553 \\ reassign(S{.x = 3});
3654 \\}
3755 , &[_][]const u8{
38 "tmp.zig:5:10: error: cannot assign to constant"
56 "tmp.zig:5:10: error: cannot assign to constant",
3957 });
4058
4159 cases.addTest("reference to const data",
......@@ -3862,14 +3880,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
38623880 "tmp.zig:1:9: error: parameter of type 'noreturn' not allowed",
38633881 });
38643882
3865 cases.add("bad assignment target",
3866 \\export fn f() void {
3867 \\ 3 = 3;
3868 \\}
3869 , &[_][]const u8{
3870 "tmp.zig:2:9: error: cannot assign to constant",
3871 });
3872
38733883 cases.add("assign to constant variable",
38743884 \\export fn f() void {
38753885 \\ const a = 3;