authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-12 12:56:25-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-12 12:56:25-04:00
logbcce77700fe0967b4dd796a3a21605868b6f9aa2
treeb3a062d4a1e3ed2e2cf103af89510670a783dd87
parent5834ff0cc58ffba8e4fe218fcf888d9f9fcf95b2

some return types disqualify comptime fn call caching

closes #828

6 files changed, 86 insertions(+), 4 deletions(-)

src/analyze.cpp+45-1
...@@ -4631,7 +4631,51 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {...@@ -4631,7 +4631,51 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {
4631 zig_unreachable();4631 zig_unreachable();
4632}4632}
46334633
4634bool fn_eval_cacheable(Scope *scope) {4634static bool return_type_is_cacheable(TypeTableEntry *return_type) {
4635 switch (return_type->id) {
4636 case TypeTableEntryIdInvalid:
4637 zig_unreachable();
4638 case TypeTableEntryIdMetaType:
4639 case TypeTableEntryIdVoid:
4640 case TypeTableEntryIdBool:
4641 case TypeTableEntryIdUnreachable:
4642 case TypeTableEntryIdInt:
4643 case TypeTableEntryIdFloat:
4644 case TypeTableEntryIdNumLitFloat:
4645 case TypeTableEntryIdNumLitInt:
4646 case TypeTableEntryIdUndefLit:
4647 case TypeTableEntryIdNullLit:
4648 case TypeTableEntryIdNamespace:
4649 case TypeTableEntryIdBoundFn:
4650 case TypeTableEntryIdFn:
4651 case TypeTableEntryIdBlock:
4652 case TypeTableEntryIdOpaque:
4653 case TypeTableEntryIdPromise:
4654 case TypeTableEntryIdErrorSet:
4655 case TypeTableEntryIdEnum:
4656 case TypeTableEntryIdPointer:
4657 return true;
4658
4659 case TypeTableEntryIdArray:
4660 case TypeTableEntryIdStruct:
4661 case TypeTableEntryIdUnion:
4662 return false;
4663
4664 case TypeTableEntryIdMaybe:
4665 return return_type_is_cacheable(return_type->data.maybe.child_type);
4666
4667 case TypeTableEntryIdErrorUnion:
4668 return return_type_is_cacheable(return_type->data.error_union.payload_type);
4669
4670 case TypeTableEntryIdArgTuple:
4671 zig_panic("TODO var args at comptime is currently not supported");
4672 }
4673 zig_unreachable();
4674}
4675
4676bool fn_eval_cacheable(Scope *scope, TypeTableEntry *return_type) {
4677 if (!return_type_is_cacheable(return_type))
4678 return false;
4635 while (scope) {4679 while (scope) {
4636 if (scope->id == ScopeIdVarDecl) {4680 if (scope->id == ScopeIdVarDecl) {
4637 ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;4681 ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;
src/analyze.hpp+1-1
...@@ -196,6 +196,6 @@ TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry);...@@ -196,6 +196,6 @@ TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry);
196uint32_t get_coro_frame_align_bytes(CodeGen *g);196uint32_t get_coro_frame_align_bytes(CodeGen *g);
197bool fn_type_can_fail(FnTypeId *fn_type_id);197bool fn_type_can_fail(FnTypeId *fn_type_id);
198bool type_can_fail(TypeTableEntry *type_entry);198bool type_can_fail(TypeTableEntry *type_entry);
199bool fn_eval_cacheable(Scope *scope);199bool fn_eval_cacheable(Scope *scope, TypeTableEntry *return_type);
200200
201#endif201#endif
src/ir.cpp+1-1
...@@ -11878,7 +11878,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -11878,7 +11878,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
11878 return_type = specified_return_type;11878 return_type = specified_return_type;
11879 }11879 }
1188011880
11881 bool cacheable = fn_eval_cacheable(exec_scope);11881 bool cacheable = fn_eval_cacheable(exec_scope, return_type);
11882 IrInstruction *result = nullptr;11882 IrInstruction *result = nullptr;
11883 if (cacheable) {11883 if (cacheable) {
11884 auto entry = ira->codegen->memoized_fn_eval_table.maybe_get(exec_scope);11884 auto entry = ira->codegen->memoized_fn_eval_table.maybe_get(exec_scope);
std/base64.zig+1-1
...@@ -369,7 +369,7 @@ fn calcDecodedSizeExactUnsafe(source: []const u8, pad_char: u8) usize {...@@ -369,7 +369,7 @@ fn calcDecodedSizeExactUnsafe(source: []const u8, pad_char: u8) usize {
369369
370370
371test "base64" {371test "base64" {
372 @setEvalBranchQuota(5000);372 @setEvalBranchQuota(8000);
373 testBase64() catch unreachable;373 testBase64() catch unreachable;
374 comptime (testBase64() catch unreachable);374 comptime (testBase64() catch unreachable);
375}375}
test/behavior.zig+1
...@@ -11,6 +11,7 @@ comptime {...@@ -11,6 +11,7 @@ comptime {
11 _ = @import("cases/bugs/394.zig");11 _ = @import("cases/bugs/394.zig");
12 _ = @import("cases/bugs/655.zig");12 _ = @import("cases/bugs/655.zig");
13 _ = @import("cases/bugs/656.zig");13 _ = @import("cases/bugs/656.zig");
14 _ = @import("cases/bugs/828.zig");
14 _ = @import("cases/cast.zig");15 _ = @import("cases/cast.zig");
15 _ = @import("cases/const_slice_child.zig");16 _ = @import("cases/const_slice_child.zig");
16 _ = @import("cases/coroutines.zig");17 _ = @import("cases/coroutines.zig");
test/cases/bugs/828.zig created+37
...@@ -0,0 +1,37 @@
1const CountBy = struct {
2 a: usize,
3
4 const One = CountBy {
5 .a = 1,
6 };
7
8 pub fn counter(self: &const CountBy) Counter {
9 return Counter {
10 .i = 0,
11 };
12 }
13};
14
15const Counter = struct {
16 i: usize,
17
18 pub fn count(self: &Counter) bool {
19 self.i += 1;
20 return self.i <= 10;
21 }
22};
23
24fn constCount(comptime cb: &const CountBy, comptime unused: u32) void {
25 comptime {
26 var cnt = cb.counter();
27 if(cnt.i != 0) @compileError("Counter instance reused!");
28 while(cnt.count()){}
29 }
30}
31
32test "comptime struct return should not return the same instance" {
33 //the first parameter must be passed by reference to trigger the bug
34 //a second parameter is required to trigger the bug
35 const ValA = constCount(&CountBy.One, 12);
36 const ValB = constCount(&CountBy.One, 15);
37}