Commit 56f8325799

Andrew Kelley <superjoe30@gmail.com>
2016-09-11 20:12:24
add compile error for assigning through const
pointer and slice closes #188
1 parent 2881123
Changed files (2)
src/analyze.cpp
@@ -2907,8 +2907,13 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import,
     return return_type;
 }
 
+enum LValPurpose {
+    LValPurposeAssign,
+    LValPurposeAddressOf,
+};
+
 static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
-        AstNode *node)
+        AstNode *node, LValPurpose purpose)
 {
     TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr,
             node->data.array_access_expr.array_ref_expr);
@@ -2923,11 +2928,20 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i
         }
         return_type = array_type->data.array.child_type;
     } else if (array_type->id == TypeTableEntryIdPointer) {
+        if (array_type->data.pointer.is_const && purpose == LValPurposeAssign) {
+            add_node_error(g, node, buf_sprintf("cannot assign to constant"));
+            return g->builtin_types.entry_invalid;
+        }
         return_type = array_type->data.pointer.child_type;
     } else if (array_type->id == TypeTableEntryIdStruct &&
                array_type->data.structure.is_slice)
     {
-        return_type = array_type->data.structure.fields[0].type_entry->data.pointer.child_type;
+        TypeTableEntry *pointer_type = array_type->data.structure.fields[0].type_entry;
+        if (pointer_type->data.pointer.is_const && purpose == LValPurposeAssign) {
+            add_node_error(g, node, buf_sprintf("cannot assign to constant"));
+            return g->builtin_types.entry_invalid;
+        }
+        return_type = pointer_type->data.pointer.child_type;
     } else {
         add_node_error(g, node,
                 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) {
     zig_unreachable();
 }
 
-enum LValPurpose {
-    LValPurposeAssign,
-    LValPurposeAddressOf,
-};
-
 static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, BlockContext *block_context,
         AstNode *lhs_node, LValPurpose purpose, bool is_ptr_const)
 {
@@ -3288,7 +3297,7 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc
             }
         }
     } else if (lhs_node->type == NodeTypeArrayAccessExpr) {
-        expected_rhs_type = analyze_array_access_expr(g, import, block_context, lhs_node);
+        expected_rhs_type = analyze_array_access_expr(g, import, block_context, lhs_node, purpose);
     } else if (lhs_node->type == NodeTypeFieldAccessExpr) {
         expected_rhs_type = analyze_field_access_expr(g, import, block_context, nullptr, lhs_node);
     } else if (lhs_node->type == NodeTypePrefixOpExpr &&
@@ -6599,7 +6608,7 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn
 
         case NodeTypeArrayAccessExpr:
             // for reading array access; assignment handled elsewhere
-            return_type = analyze_array_access_expr(g, import, context, node);
+            return_type = analyze_array_access_expr(g, import, context, node, LValPurposeAddressOf);
             break;
         case NodeTypeSliceExpr:
             return_type = analyze_slice_expr(g, import, context, node);
test/run_tests.cpp
@@ -1467,6 +1467,20 @@ fn f(foo: &const Foo) {
     foo.method(1, 2);
 }
     )SOURCE", 1, ".tmp_source.zig:7:15: error: expected 1 arguments, got 2");
+
+    add_compile_fail_case("assign through constant pointer", R"SOURCE(
+fn f() {
+  var cstr = c"Hat";
+  cstr[0] = 'W';
+}
+    )SOURCE", 1, ".tmp_source.zig:4:7: error: cannot assign to constant");
+
+    add_compile_fail_case("assign through constant slice", R"SOURCE(
+pub fn f() {
+  var cstr: []const u8 = "Hat";
+  cstr[0] = 'W';
+}
+    )SOURCE", 1, ".tmp_source.zig:4:7: error: cannot assign to constant");
 }
 
 //////////////////////////////////////////////////////////////////////////////