authorgravatar for matthew.mcallister.0@gmail.comMatthew McAllister <matthew.mcallister.0@gmail.com> 2019-02-12 21:22:16-08:00
committergravatar for matthew.mcallister.0@gmail.comMatthew McAllister <matthew.mcallister.0@gmail.com> 2019-02-16 17:37:47-08:00
log91989e70ba68e3543acffef079d97c9416b5259c
tree71323c9859706b377290c5bbca22c661afaf60dc
parentc3c92ca8b1ada4faed14a9770ab7ed6536edaa15

Fix lvalue dereference type checking

Previously, if a dereference instruction was an lvalue, it would fail to typecheck that the value being dereferenced was indeed a pointer. Although a little clunky, this change obviates the need for redundant type checks scattered about the analysis.

3 files changed, 45 insertions(+), 29 deletions(-)

src/all_types.hpp+6-5
...@@ -2091,6 +2091,11 @@ struct IrBasicBlock {...@@ -2091,6 +2091,11 @@ struct IrBasicBlock {
2091 IrInstruction *must_be_comptime_source_instr;2091 IrInstruction *must_be_comptime_source_instr;
2092};2092};
20932093
2094enum LVal {
2095 LValNone,
2096 LValPtr,
2097};
2098
2094// These instructions are in transition to having "pass 1" instructions2099// These instructions are in transition to having "pass 1" instructions
2095// and "pass 2" instructions. The pass 1 instructions are suffixed with Src2100// and "pass 2" instructions. The pass 1 instructions are suffixed with Src
2096// and pass 2 are suffixed with Gen.2101// and pass 2 are suffixed with Gen.
...@@ -2354,6 +2359,7 @@ struct IrInstructionUnOp {...@@ -2354,6 +2359,7 @@ struct IrInstructionUnOp {
23542359
2355 IrUnOp op_id;2360 IrUnOp op_id;
2356 IrInstruction *value;2361 IrInstruction *value;
2362 LVal lval;
2357};2363};
23582364
2359enum IrBinOp {2365enum IrBinOp {
...@@ -3090,11 +3096,6 @@ struct IrInstructionTypeName {...@@ -3090,11 +3096,6 @@ struct IrInstructionTypeName {
3090 IrInstruction *type_value;3096 IrInstruction *type_value;
3091};3097};
30923098
3093enum LVal {
3094 LValNone,
3095 LValPtr,
3096};
3097
3098struct IrInstructionDeclRef {3099struct IrInstructionDeclRef {
3099 IrInstruction base;3100 IrInstruction base;
31003101
src/ir.cpp+18-21
...@@ -1307,6 +1307,7 @@ static IrInstruction *ir_build_un_op(IrBuilder *irb, Scope *scope, AstNode *sour...@@ -1307,6 +1307,7 @@ static IrInstruction *ir_build_un_op(IrBuilder *irb, Scope *scope, AstNode *sour
1307 IrInstructionUnOp *br_instruction = ir_build_instruction<IrInstructionUnOp>(irb, scope, source_node);1307 IrInstructionUnOp *br_instruction = ir_build_instruction<IrInstructionUnOp>(irb, scope, source_node);
1308 br_instruction->op_id = op_id;1308 br_instruction->op_id = op_id;
1309 br_instruction->value = value;1309 br_instruction->value = value;
1310 br_instruction->lval = LValNone;
13101311
1311 ir_ref_instruction(value, irb->current_basic_block);1312 ir_ref_instruction(value, irb->current_basic_block);
13121313
...@@ -7223,7 +7224,13 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop...@@ -7223,7 +7224,13 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
7223 if (value == irb->codegen->invalid_instruction)7224 if (value == irb->codegen->invalid_instruction)
7224 return value;7225 return value;
72257226
7226 return ir_build_un_op(irb, scope, node, IrUnOpDereference, value);7227 // We essentially just converted any lvalue from &(x.*) to (&x).*;
7228 // this inhibits checking that x is a pointer later, so we directly
7229 // record whether the pointer check is needed
7230 IrInstructionUnOp *result = (IrInstructionUnOp*)ir_build_un_op(irb, scope, node, IrUnOpDereference, value);
7231 result->lval = lval;
7232
7233 return &result->base;
7227 }7234 }
7228 case NodeTypeUnwrapOptional: {7235 case NodeTypeUnwrapOptional: {
7229 AstNode *expr_node = node->data.unwrap_optional.expr;7236 AstNode *expr_node = node->data.unwrap_optional.expr;
...@@ -11437,7 +11444,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc...@@ -11437,7 +11444,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
11437 return load_ptr_instruction;11444 return load_ptr_instruction;
11438 } else {11445 } else {
11439 ir_add_error_node(ira, source_instruction->source_node,11446 ir_add_error_node(ira, source_instruction->source_node,
11440 buf_sprintf("attempt to dereference non pointer type '%s'",11447 buf_sprintf("attempt to dereference non-pointer type '%s'",
11441 buf_ptr(&type_entry->name)));11448 buf_ptr(&type_entry->name)));
11442 return ira->codegen->invalid_instruction;11449 return ira->codegen->invalid_instruction;
11443 }11450 }
...@@ -13616,12 +13623,6 @@ no_mem_slot:...@@ -13616,12 +13623,6 @@ no_mem_slot:
13616static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,13623static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
13617 IrInstruction *ptr, IrInstruction *uncasted_value)13624 IrInstruction *ptr, IrInstruction *uncasted_value)
13618{13625{
13619 if (ptr->value.type->id != ZigTypeIdPointer) {
13620 ir_add_error(ira, ptr,
13621 buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name)));
13622 return ira->codegen->invalid_instruction;
13623 }
13624
13625 if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) {13626 if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) {
13626 return ir_const_void(ira, source_instr);13627 return ir_const_void(ira, source_instr);
13627 }13628 }
...@@ -14550,11 +14551,18 @@ static IrInstruction *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstruction...@@ -14550,11 +14551,18 @@ static IrInstruction *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstruction
14550 buf_ptr(&ptr_type->name)));14551 buf_ptr(&ptr_type->name)));
14551 return ira->codegen->invalid_instruction;14552 return ira->codegen->invalid_instruction;
14552 }14553 }
14553 // this dereference is always an rvalue because in the IR gen we identify lvalue and emit14554
14554 // one of the ptr instructions
14555 IrInstruction *result = ir_get_deref(ira, &instruction->base, ptr);14555 IrInstruction *result = ir_get_deref(ira, &instruction->base, ptr);
14556 if (result == ira->codegen->invalid_instruction)14556 if (result == ira->codegen->invalid_instruction)
14557 return ira->codegen->invalid_instruction;14557 return ira->codegen->invalid_instruction;
14558
14559 // If the result needs to be an lvalue, type check it
14560 if (instruction->lval == LValPtr && result->value.type->id != ZigTypeIdPointer) {
14561 ir_add_error(ira, &instruction->base,
14562 buf_sprintf("attempt to dereference non-pointer type '%s'", buf_ptr(&result->value.type->name)));
14563 return ira->codegen->invalid_instruction;
14564 }
14565
14558 return result;14566 return result;
14559 }14567 }
14560 case IrUnOpOptional:14568 case IrUnOpOptional:
...@@ -15380,12 +15388,6 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc...@@ -15380,12 +15388,6 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
15380 if (type_is_invalid(container_ptr->value.type))15388 if (type_is_invalid(container_ptr->value.type))
15381 return ira->codegen->invalid_instruction;15389 return ira->codegen->invalid_instruction;
1538215390
15383 if (container_ptr->value.type->id != ZigTypeIdPointer) {
15384 ir_add_error_node(ira, field_ptr_instruction->base.source_node,
15385 buf_sprintf("attempt to dereference non-pointer type '%s'",
15386 buf_ptr(&container_ptr->value.type->name)));
15387 return ira->codegen->invalid_instruction;
15388 }
15389 ZigType *container_type = container_ptr->value.type->data.pointer.child_type;15391 ZigType *container_type = container_ptr->value.type->data.pointer.child_type;
1539015392
15391 Buf *field_name = field_ptr_instruction->field_name_buffer;15393 Buf *field_name = field_ptr_instruction->field_name_buffer;
...@@ -16596,11 +16598,6 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,...@@ -16596,11 +16598,6 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
16596 return ir_const_type(ira, &switch_target_instruction->base, ptr_type->data.pointer.child_type);16598 return ir_const_type(ira, &switch_target_instruction->base, ptr_type->data.pointer.child_type);
16597 }16599 }
1659816600
16599 if (target_value_ptr->value.type->id != ZigTypeIdPointer) {
16600 ir_add_error(ira, target_value_ptr, buf_sprintf("invalid deref on switch target"));
16601 return ira->codegen->invalid_instruction;
16602 }
16603
16604 ZigType *target_type = target_value_ptr->value.type->data.pointer.child_type;16601 ZigType *target_type = target_value_ptr->value.type->data.pointer.child_type;
16605 ConstExprValue *pointee_val = nullptr;16602 ConstExprValue *pointee_val = nullptr;
16606 if (instr_is_comptime(target_value_ptr)) {16603 if (instr_is_comptime(target_value_ptr)) {
test/compile_errors.zig+21-3
...@@ -137,6 +137,24 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -137,6 +137,24 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
137 ".tmp_source.zig:3:15: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'",137 ".tmp_source.zig:3:15: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'",
138 );138 );
139139
140 cases.addTest(
141 "assign to invalid dereference",
142 \\export fn entry() void {
143 \\ 'a'.* = 1;
144 \\}
145 ,
146 ".tmp_source.zig:2:8: error: attempt to dereference non-pointer type 'comptime_int'",
147 );
148
149 cases.addTest(
150 "take slice of invalid dereference",
151 \\export fn entry() void {
152 \\ const x = 'a'.*[0..];
153 \\}
154 ,
155 ".tmp_source.zig:2:18: error: attempt to dereference non-pointer type 'comptime_int'",
156 );
157
140 cases.addTest(158 cases.addTest(
141 "@truncate undefined value",159 "@truncate undefined value",
142 \\export fn entry() void {160 \\export fn entry() void {
...@@ -447,7 +465,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -447,7 +465,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
447 \\ _ = a.*.len;465 \\ _ = a.*.len;
448 \\}466 \\}
449 ,467 ,
450 ".tmp_source.zig:3:12: error: attempt to dereference non-pointer type '[]u8'",468 ".tmp_source.zig:3:10: error: attempt to dereference non-pointer type '[]u8'",
451 );469 );
452470
453 cases.add(471 cases.add(
...@@ -1158,7 +1176,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1158,7 +1176,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1158 \\ Filled,1176 \\ Filled,
1159 \\};1177 \\};
1160 ,1178 ,
1161 ".tmp_source.zig:3:17: error: invalid deref on switch target",1179 ".tmp_source.zig:3:17: error: attempt to dereference non-pointer type 'Tile'",
1162 );1180 );
11631181
1164 cases.add(1182 cases.add(
...@@ -4000,7 +4018,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4000,7 +4018,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4000 \\4018 \\
4001 \\export fn entry() usize { return @sizeOf(@typeOf(pass)); }4019 \\export fn entry() usize { return @sizeOf(@typeOf(pass)); }
4002 ,4020 ,
4003 ".tmp_source.zig:4:10: error: attempt to dereference non pointer type '[10]u8'",4021 ".tmp_source.zig:4:10: error: attempt to dereference non-pointer type '[10]u8'",
4004 );4022 );
40054023
4006 cases.add(4024 cases.add(