| ... | @@ -2907,8 +2907,13 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -2907,8 +2907,13 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, |
| 2907 | return return_type; | 2907 | return return_type; |
| 2908 | } | 2908 | } |
| 2909 | | 2909 | |
| | 2910 | enum LValPurpose { |
| | 2911 | LValPurposeAssign, |
| | 2912 | LValPurposeAddressOf, |
| | 2913 | }; |
| | 2914 | |
| 2910 | static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 2915 | static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 2911 | AstNode *node) | 2916 | AstNode *node, LValPurpose purpose) |
| 2912 | { | 2917 | { |
| 2913 | TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr, | 2918 | TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr, |
| 2914 | node->data.array_access_expr.array_ref_expr); | 2919 | node->data.array_access_expr.array_ref_expr); |
| ... | @@ -2923,11 +2928,20 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i | ... | @@ -2923,11 +2928,20 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i |
| 2923 | } | 2928 | } |
| 2924 | return_type = array_type->data.array.child_type; | 2929 | return_type = array_type->data.array.child_type; |
| 2925 | } else if (array_type->id == TypeTableEntryIdPointer) { | 2930 | } else if (array_type->id == TypeTableEntryIdPointer) { |
| | 2931 | if (array_type->data.pointer.is_const && purpose == LValPurposeAssign) { |
| | 2932 | add_node_error(g, node, buf_sprintf("cannot assign to constant")); |
| | 2933 | return g->builtin_types.entry_invalid; |
| | 2934 | } |
| 2926 | return_type = array_type->data.pointer.child_type; | 2935 | return_type = array_type->data.pointer.child_type; |
| 2927 | } else if (array_type->id == TypeTableEntryIdStruct && | 2936 | } else if (array_type->id == TypeTableEntryIdStruct && |
| 2928 | array_type->data.structure.is_slice) | 2937 | array_type->data.structure.is_slice) |
| 2929 | { | 2938 | { |
| 2930 | return_type = array_type->data.structure.fields[0].type_entry->data.pointer.child_type; | 2939 | TypeTableEntry *pointer_type = array_type->data.structure.fields[0].type_entry; |
| | 2940 | if (pointer_type->data.pointer.is_const && purpose == LValPurposeAssign) { |
| | 2941 | add_node_error(g, node, buf_sprintf("cannot assign to constant")); |
| | 2942 | return g->builtin_types.entry_invalid; |
| | 2943 | } |
| | 2944 | return_type = pointer_type->data.pointer.child_type; |
| 2931 | } else { | 2945 | } else { |
| 2932 | add_node_error(g, node, | 2946 | add_node_error(g, node, |
| 2933 | buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name))); | 2947 | buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name))); |
| ... | @@ -3254,11 +3268,6 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) { | ... | @@ -3254,11 +3268,6 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) { |
| 3254 | zig_unreachable(); | 3268 | zig_unreachable(); |
| 3255 | } | 3269 | } |
| 3256 | | 3270 | |
| 3257 | enum LValPurpose { | | |
| 3258 | LValPurposeAssign, | | |
| 3259 | LValPurposeAddressOf, | | |
| 3260 | }; | | |
| 3261 | | | |
| 3262 | static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, BlockContext *block_context, | 3271 | static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, BlockContext *block_context, |
| 3263 | AstNode *lhs_node, LValPurpose purpose, bool is_ptr_const) | 3272 | AstNode *lhs_node, LValPurpose purpose, bool is_ptr_const) |
| 3264 | { | 3273 | { |
| ... | @@ -3288,7 +3297,7 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc | ... | @@ -3288,7 +3297,7 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc |
| 3288 | } | 3297 | } |
| 3289 | } | 3298 | } |
| 3290 | } else if (lhs_node->type == NodeTypeArrayAccessExpr) { | 3299 | } else if (lhs_node->type == NodeTypeArrayAccessExpr) { |
| 3291 | expected_rhs_type = analyze_array_access_expr(g, import, block_context, lhs_node); | 3300 | expected_rhs_type = analyze_array_access_expr(g, import, block_context, lhs_node, purpose); |
| 3292 | } else if (lhs_node->type == NodeTypeFieldAccessExpr) { | 3301 | } else if (lhs_node->type == NodeTypeFieldAccessExpr) { |
| 3293 | expected_rhs_type = analyze_field_access_expr(g, import, block_context, nullptr, lhs_node); | 3302 | expected_rhs_type = analyze_field_access_expr(g, import, block_context, nullptr, lhs_node); |
| 3294 | } else if (lhs_node->type == NodeTypePrefixOpExpr && | 3303 | } else if (lhs_node->type == NodeTypePrefixOpExpr && |
| ... | @@ -6599,7 +6608,7 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn | ... | @@ -6599,7 +6608,7 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn |
| 6599 | | 6608 | |
| 6600 | case NodeTypeArrayAccessExpr: | 6609 | case NodeTypeArrayAccessExpr: |
| 6601 | // for reading array access; assignment handled elsewhere | 6610 | // for reading array access; assignment handled elsewhere |
| 6602 | return_type = analyze_array_access_expr(g, import, context, node); | 6611 | return_type = analyze_array_access_expr(g, import, context, node, LValPurposeAddressOf); |
| 6603 | break; | 6612 | break; |
| 6604 | case NodeTypeSliceExpr: | 6613 | case NodeTypeSliceExpr: |
| 6605 | return_type = analyze_slice_expr(g, import, context, node); | 6614 | return_type = analyze_slice_expr(g, import, context, node); |