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 {
20912091 IrInstruction *must_be_comptime_source_instr;
20922092};
20932093
2094enum LVal {
2095 LValNone,
2096 LValPtr,
2097};
2098
20942099// These instructions are in transition to having "pass 1" instructions
20952100// and "pass 2" instructions. The pass 1 instructions are suffixed with Src
20962101// and pass 2 are suffixed with Gen.
......@@ -2354,6 +2359,7 @@ struct IrInstructionUnOp {
23542359
23552360 IrUnOp op_id;
23562361 IrInstruction *value;
2362 LVal lval;
23572363};
23582364
23592365enum IrBinOp {
......@@ -3090,11 +3096,6 @@ struct IrInstructionTypeName {
30903096 IrInstruction *type_value;
30913097};
30923098
3093enum LVal {
3094 LValNone,
3095 LValPtr,
3096};
3097
30983099struct IrInstructionDeclRef {
30993100 IrInstruction base;
31003101
src/ir.cpp+18-21
......@@ -1307,6 +1307,7 @@ static IrInstruction *ir_build_un_op(IrBuilder *irb, Scope *scope, AstNode *sour
13071307 IrInstructionUnOp *br_instruction = ir_build_instruction<IrInstructionUnOp>(irb, scope, source_node);
13081308 br_instruction->op_id = op_id;
13091309 br_instruction->value = value;
1310 br_instruction->lval = LValNone;
13101311
13111312 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
72237224 if (value == irb->codegen->invalid_instruction)
72247225 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;
72277234 }
72287235 case NodeTypeUnwrapOptional: {
72297236 AstNode *expr_node = node->data.unwrap_optional.expr;
......@@ -11437,7 +11444,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
1143711444 return load_ptr_instruction;
1143811445 } else {
1143911446 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'",
1144111448 buf_ptr(&type_entry->name)));
1144211449 return ira->codegen->invalid_instruction;
1144311450 }
......@@ -13616,12 +13623,6 @@ no_mem_slot:
1361613623static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
1361713624 IrInstruction *ptr, IrInstruction *uncasted_value)
1361813625{
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
1362513626 if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) {
1362613627 return ir_const_void(ira, source_instr);
1362713628 }
......@@ -14550,11 +14551,18 @@ static IrInstruction *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstruction
1455014551 buf_ptr(&ptr_type->name)));
1455114552 return ira->codegen->invalid_instruction;
1455214553 }
14553 // this dereference is always an rvalue because in the IR gen we identify lvalue and emit
14554 // one of the ptr instructions
14554
1455514555 IrInstruction *result = ir_get_deref(ira, &instruction->base, ptr);
1455614556 if (result == ira->codegen->invalid_instruction)
1455714557 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
1455814566 return result;
1455914567 }
1456014568 case IrUnOpOptional:
......@@ -15380,12 +15388,6 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
1538015388 if (type_is_invalid(container_ptr->value.type))
1538115389 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 }
1538915391 ZigType *container_type = container_ptr->value.type->data.pointer.child_type;
1539015392
1539115393 Buf *field_name = field_ptr_instruction->field_name_buffer;
......@@ -16596,11 +16598,6 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
1659616598 return ir_const_type(ira, &switch_target_instruction->base, ptr_type->data.pointer.child_type);
1659716599 }
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
1660416601 ZigType *target_type = target_value_ptr->value.type->data.pointer.child_type;
1660516602 ConstExprValue *pointee_val = nullptr;
1660616603 if (instr_is_comptime(target_value_ptr)) {
test/compile_errors.zig+21-3
......@@ -137,6 +137,24 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
137137 ".tmp_source.zig:3:15: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'",
138138 );
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
140158 cases.addTest(
141159 "@truncate undefined value",
142160 \\export fn entry() void {
......@@ -447,7 +465,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
447465 \\ _ = a.*.len;
448466 \\}
449467 ,
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'",
451469 );
452470
453471 cases.add(
......@@ -1158,7 +1176,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
11581176 \\ Filled,
11591177 \\};
11601178 ,
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'",
11621180 );
11631181
11641182 cases.add(
......@@ -4000,7 +4018,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
40004018 \\
40014019 \\export fn entry() usize { return @sizeOf(@typeOf(pass)); }
40024020 ,
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'",
40044022 );
40054023
40064024 cases.add(