authorgravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2017-04-23 16:59:55-07:00
committergravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2017-04-23 21:15:15-07:00
logc6605cba8375871a145896f9cf1090e9c823214a
treef6309057804dc9fd6d5fa10feafb9d8f6a44a713
parent6de33ded81981554ccffc3ecbfcd5b0f628cf502

blocks check that their statements are void

closes #291 This changes the error message "return value ignored" to "expression value is ignored". This is because this error also applies to {1;}, which has no function calls. Also fix ignored expression values in std and test. This caught a bug in debug.readAllocBytes where an early Eof error would have been missed. See #219.

11 files changed, 80 insertions(+), 22 deletions(-)

src/all_types.hpp+7
......@@ -1738,6 +1738,7 @@ enum IrInstructionId {
17381738 IrInstructionIdIntToErr,
17391739 IrInstructionIdErrToInt,
17401740 IrInstructionIdCheckSwitchProngs,
1741 IrInstructionIdCheckStatementIsVoid,
17411742 IrInstructionIdTestType,
17421743 IrInstructionIdTypeName,
17431744 IrInstructionIdCanImplicitCast,
......@@ -2435,6 +2436,12 @@ struct IrInstructionCheckSwitchProngs {
24352436 size_t range_count;
24362437};
24372438
2439struct IrInstructionCheckStatementIsVoid {
2440 IrInstruction base;
2441
2442 IrInstruction *statement_value;
2443};
2444
24382445struct IrInstructionTestType {
24392446 IrInstruction base;
24402447
src/codegen.cpp+1
......@@ -2885,6 +2885,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
28852885 case IrInstructionIdTestComptime:
28862886 case IrInstructionIdGeneratedCode:
28872887 case IrInstructionIdCheckSwitchProngs:
2888 case IrInstructionIdCheckStatementIsVoid:
28882889 case IrInstructionIdTestType:
28892890 case IrInstructionIdTypeName:
28902891 case IrInstructionIdCanImplicitCast:
src/ir.cpp+48-13
......@@ -510,6 +510,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckSwitchProng
510510 return IrInstructionIdCheckSwitchProngs;
511511}
512512
513static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckStatementIsVoid *) {
514 return IrInstructionIdCheckStatementIsVoid;
515}
516
513517static constexpr IrInstructionId ir_instruction_id(IrInstructionTestType *) {
514518 return IrInstructionIdTestType;
515519}
......@@ -2803,6 +2807,15 @@ static IrInstruction *ir_instruction_checkswitchprongs_get_dep(IrInstructionChec
28032807 return nullptr;
28042808}
28052809
2810static IrInstruction *ir_instruction_checkstatementisvoid_get_dep(IrInstructionCheckStatementIsVoid *instruction,
2811 size_t index)
2812{
2813 switch (index) {
2814 case 0: return instruction->statement_value;
2815 default: return nullptr;
2816 }
2817}
2818
28062819static IrInstruction *ir_instruction_testtype_get_dep(IrInstructionTestType *instruction, size_t index) {
28072820 switch (index) {
28082821 case 0: return instruction->type_value;
......@@ -3060,6 +3073,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
30603073 return ir_instruction_errtoint_get_dep((IrInstructionErrToInt *) instruction, index);
30613074 case IrInstructionIdCheckSwitchProngs:
30623075 return ir_instruction_checkswitchprongs_get_dep((IrInstructionCheckSwitchProngs *) instruction, index);
3076 case IrInstructionIdCheckStatementIsVoid:
3077 return ir_instruction_checkstatementisvoid_get_dep((IrInstructionCheckStatementIsVoid *) instruction, index);
30633078 case IrInstructionIdTestType:
30643079 return ir_instruction_testtype_get_dep((IrInstructionTestType *) instruction, index);
30653080 case IrInstructionIdTypeName:
......@@ -3333,6 +3348,18 @@ static ScopeBlock *find_block_scope(IrExecutable *exec, Scope *scope) {
33333348 return nullptr;
33343349}
33353350
3351static IrInstruction *ir_build_check_statement_is_void(IrBuilder *irb, Scope *scope, AstNode *source_node,
3352 IrInstruction* statement_value)
3353{
3354 IrInstructionCheckStatementIsVoid *instruction = ir_build_instruction<IrInstructionCheckStatementIsVoid>(
3355 irb, scope, source_node);
3356 instruction->statement_value = statement_value;
3357
3358 ir_ref_instruction(statement_value, irb->current_basic_block);
3359
3360 return &instruction->base;
3361}
3362
33363363static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node) {
33373364 assert(block_node->type == NodeTypeBlock);
33383365
......@@ -3410,12 +3437,8 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
34103437 return_value = statement_value;
34113438 } else {
34123439 // there are more statements ahead of this one. this statement's value must be void
3413 TypeTableEntry *instruction_type = statement_value->value.type;
3414 if (instruction_type &&
3415 instruction_type->id != TypeTableEntryIdInvalid &&
3416 instruction_type->id != TypeTableEntryIdVoid &&
3417 instruction_type->id != TypeTableEntryIdUnreachable) {
3418 add_node_error(irb->codegen, statement_node, buf_sprintf("expression valued ignored"));
3440 if (statement_value != irb->codegen->invalid_instruction) {
3441 ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, statement_node, statement_value));
34193442 }
34203443 }
34213444 }
......@@ -12640,6 +12663,22 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
1264012663 return ira->codegen->builtin_types.entry_void;
1264112664}
1264212665
12666static TypeTableEntry *ir_analyze_instruction_check_statement_is_void(IrAnalyze *ira,
12667 IrInstructionCheckStatementIsVoid *instruction)
12668{
12669 IrInstruction *statement_value = instruction->statement_value;
12670 TypeTableEntry *statement_type = statement_value->value.type;
12671 if (type_is_invalid(statement_type))
12672 return ira->codegen->builtin_types.entry_invalid;
12673
12674 if (statement_type->id != TypeTableEntryIdVoid) {
12675 ir_add_error(ira, &instruction->base, buf_sprintf("expression value is ignored"));
12676 }
12677
12678 ir_build_const_from(ira, &instruction->base);
12679 return ira->codegen->builtin_types.entry_void;
12680}
12681
1264312682static TypeTableEntry *ir_analyze_instruction_test_type(IrAnalyze *ira, IrInstructionTestType *instruction) {
1264412683 IrInstruction *type_value = instruction->type_value->other;
1264512684 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
......@@ -12987,6 +13026,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1298713026 return ir_analyze_instruction_test_comptime(ira, (IrInstructionTestComptime *)instruction);
1298813027 case IrInstructionIdCheckSwitchProngs:
1298913028 return ir_analyze_instruction_check_switch_prongs(ira, (IrInstructionCheckSwitchProngs *)instruction);
13029 case IrInstructionIdCheckStatementIsVoid:
13030 return ir_analyze_instruction_check_statement_is_void(ira, (IrInstructionCheckStatementIsVoid *)instruction);
1299013031 case IrInstructionIdTestType:
1299113032 return ir_analyze_instruction_test_type(ira, (IrInstructionTestType *)instruction);
1299213033 case IrInstructionIdCanImplicitCast:
......@@ -13026,13 +13067,6 @@ static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *ins
1302613067 instruction_type->id == TypeTableEntryIdUnreachable);
1302713068 instruction->other = instruction;
1302813069 }
13029 if (instruction_type->id != TypeTableEntryIdInvalid &&
13030 instruction_type->id != TypeTableEntryIdVoid &&
13031 instruction_type->id != TypeTableEntryIdUnreachable &&
13032 instruction->ref_count == 0)
13033 {
13034 ir_add_error(ira, instruction, buf_sprintf("return value ignored"));
13035 }
1303613070
1303713071 return instruction_type;
1303813072}
......@@ -13123,6 +13157,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1312313157 case IrInstructionIdBreakpoint:
1312413158 case IrInstructionIdOverflowOp: // TODO when we support multiple returns this can be side effect free
1312513159 case IrInstructionIdCheckSwitchProngs:
13160 case IrInstructionIdCheckStatementIsVoid:
1312613161 case IrInstructionIdSetGlobalAlign:
1312713162 case IrInstructionIdSetGlobalSection:
1312813163 case IrInstructionIdSetGlobalLinkage:
src/ir_print.cpp+9
......@@ -814,6 +814,12 @@ static void ir_print_check_switch_prongs(IrPrint *irp, IrInstructionCheckSwitchP
814814 fprintf(irp->f, ")");
815815}
816816
817static void ir_print_check_statement_is_void(IrPrint *irp, IrInstructionCheckStatementIsVoid *instruction) {
818 fprintf(irp->f, "@checkStatementIsVoid(");
819 ir_print_other_instruction(irp, instruction->statement_value);
820 fprintf(irp->f, ")");
821}
822
817823static void ir_print_test_type(IrPrint *irp, IrInstructionTestType *instruction) {
818824 fprintf(irp->f, "testtype ");
819825 ir_print_other_instruction(irp, instruction->type_value);
......@@ -1149,6 +1155,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
11491155 case IrInstructionIdCheckSwitchProngs:
11501156 ir_print_check_switch_prongs(irp, (IrInstructionCheckSwitchProngs *)instruction);
11511157 break;
1158 case IrInstructionIdCheckStatementIsVoid:
1159 ir_print_check_statement_is_void(irp, (IrInstructionCheckStatementIsVoid *)instruction);
1160 break;
11521161 case IrInstructionIdTestType:
11531162 ir_print_test_type(irp, (IrInstructionTestType *)instruction);
11541163 break;
std/buf_map.zig+2-2
......@@ -31,14 +31,14 @@ pub const BufMap = struct {
3131 test (self.hash_map.get(key)) |entry| {
3232 const value_copy = %return self.copy(value);
3333 %defer self.free(value_copy);
34 %return self.hash_map.put(key, value_copy);
34 _ = %return self.hash_map.put(key, value_copy);
3535 self.free(entry.value);
3636 } else {
3737 const key_copy = %return self.copy(key);
3838 %defer self.free(key_copy);
3939 const value_copy = %return self.copy(value);
4040 %defer self.free(value_copy);
41 %return self.hash_map.put(key_copy, value_copy);
41 _ = %return self.hash_map.put(key_copy, value_copy);
4242 }
4343 }
4444
std/buf_set.zig+1-1
......@@ -28,7 +28,7 @@ pub const BufSet = struct {
2828 if (self.hash_map.get(key) == null) {
2929 const key_copy = %return self.copy(key);
3030 %defer self.free(key_copy);
31 %return self.hash_map.put(key_copy, {});
31 _ = %return self.hash_map.put(key_copy, {});
3232 }
3333 }
3434
std/build.zig+5-2
......@@ -415,20 +415,23 @@ pub const Builder = struct {
415415 .value = UserValue.Scalar { value },
416416 .used = false,
417417 })) |*prev_value| {
418 // option already exists
418419 switch (prev_value.value) {
419420 UserValue.Scalar => |s| {
421 // turn it into a list
420422 var list = List([]const u8).init(self.allocator);
421423 %%list.append(s);
422424 %%list.append(value);
423 %%self.user_input_options.put(name, UserInputOption {
425 _ = %%self.user_input_options.put(name, UserInputOption {
424426 .name = name,
425427 .value = UserValue.List { list },
426428 .used = false,
427429 });
428430 },
429431 UserValue.List => |*list| {
432 // append to the list
430433 %%list.append(value);
431 %%self.user_input_options.put(name, UserInputOption {
434 _ = %%self.user_input_options.put(name, UserInputOption {
432435 .name = name,
433436 .value = UserValue.List { *list },
434437 .used = false,
std/debug.zig+1-1
......@@ -217,7 +217,7 @@ fn getString(st: &ElfStackTrace, offset: u64) -> %[]u8 {
217217fn readAllocBytes(in_stream: &io.InStream, size: usize) -> %[]u8 {
218218 const buf = %return global_allocator.alloc(u8, size);
219219 %defer global_allocator.free(buf);
220 %return in_stream.read(buf);
220 if (size < %return in_stream.read(buf)) return error.Eof;
221221 return buf;
222222}
223223
std/fmt.zig+1-1
......@@ -386,7 +386,7 @@ fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, width: u
386386}
387387
388388test "testParseU64DigitTooBig" {
389 parseUnsigned(u64, "123a", 10) %% |err| {
389 _ = parseUnsigned(u64, "123a", 10) %% |err| {
390390 if (err == error.InvalidChar) return;
391391 unreachable;
392392 };
test/cases/switch_prong_err_enum.zig+4-1
......@@ -22,6 +22,9 @@ fn doThing(form_id: u64) -> %FormValue {
2222}
2323
2424test "switchProngReturnsErrorEnum" {
25 %%doThing(17);
25 switch (%%doThing(17)) {
26 FormValue.Address => |payload| { assert(payload == 1); },
27 else => unreachable,
28 }
2629 assert(read_count == 1);
2730}
test/compile_errors.zig+1-1
......@@ -1346,7 +1346,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
13461346 \\ bar();
13471347 \\}
13481348 \\fn bar() -> i32 { 0 }
1349 , ".tmp_source.zig:2:8: error: return value ignored");
1349 , ".tmp_source.zig:2:8: error: expression value is ignored");
13501350
13511351 cases.add("integer literal on a non-comptime var",
13521352 \\export fn foo() {