zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit bcce77700fe0967b4dd796a3a21605868b6f9aa2 (tree)
parent 5834ff0cc58ffba8e4fe218fcf888d9f9fcf95b2
Author: Andrew Kelley <superjoe30@gmail.com>
Date:   Mon, 12 Mar 2018 12:56:25 -0400

some return types disqualify comptime fn call caching

closes #828

Diffstat:
Msrc/analyze.cpp | 46+++++++++++++++++++++++++++++++++++++++++++++-
Msrc/analyze.hpp | 2+-
Msrc/ir.cpp | 2+-
Mstd/base64.zig | 2+-
Mtest/behavior.zig | 1+
Atest/cases/bugs/828.zig | 37+++++++++++++++++++++++++++++++++++++
6 files changed, 86 insertions(+), 4 deletions(-)

diff --git a/src/analyze.cpp b/src/analyze.cpp @@ -4631,7 +4631,51 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) { zig_unreachable(); } -bool fn_eval_cacheable(Scope *scope) { +static bool return_type_is_cacheable(TypeTableEntry *return_type) { + switch (return_type->id) { + case TypeTableEntryIdInvalid: + zig_unreachable(); + case TypeTableEntryIdMetaType: + case TypeTableEntryIdVoid: + case TypeTableEntryIdBool: + case TypeTableEntryIdUnreachable: + case TypeTableEntryIdInt: + case TypeTableEntryIdFloat: + case TypeTableEntryIdNumLitFloat: + case TypeTableEntryIdNumLitInt: + case TypeTableEntryIdUndefLit: + case TypeTableEntryIdNullLit: + case TypeTableEntryIdNamespace: + case TypeTableEntryIdBoundFn: + case TypeTableEntryIdFn: + case TypeTableEntryIdBlock: + case TypeTableEntryIdOpaque: + case TypeTableEntryIdPromise: + case TypeTableEntryIdErrorSet: + case TypeTableEntryIdEnum: + case TypeTableEntryIdPointer: + return true; + + case TypeTableEntryIdArray: + case TypeTableEntryIdStruct: + case TypeTableEntryIdUnion: + return false; + + case TypeTableEntryIdMaybe: + return return_type_is_cacheable(return_type->data.maybe.child_type); + + case TypeTableEntryIdErrorUnion: + return return_type_is_cacheable(return_type->data.error_union.payload_type); + + case TypeTableEntryIdArgTuple: + zig_panic("TODO var args at comptime is currently not supported"); + } + zig_unreachable(); +} + +bool fn_eval_cacheable(Scope *scope, TypeTableEntry *return_type) { + if (!return_type_is_cacheable(return_type)) + return false; while (scope) { if (scope->id == ScopeIdVarDecl) { ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; diff --git a/src/analyze.hpp b/src/analyze.hpp @@ -196,6 +196,6 @@ TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry); uint32_t get_coro_frame_align_bytes(CodeGen *g); bool fn_type_can_fail(FnTypeId *fn_type_id); bool type_can_fail(TypeTableEntry *type_entry); -bool fn_eval_cacheable(Scope *scope); +bool fn_eval_cacheable(Scope *scope, TypeTableEntry *return_type); #endif diff --git a/src/ir.cpp b/src/ir.cpp @@ -11878,7 +11878,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal return_type = specified_return_type; } - bool cacheable = fn_eval_cacheable(exec_scope); + bool cacheable = fn_eval_cacheable(exec_scope, return_type); IrInstruction *result = nullptr; if (cacheable) { auto entry = ira->codegen->memoized_fn_eval_table.maybe_get(exec_scope); diff --git a/std/base64.zig b/std/base64.zig @@ -369,7 +369,7 @@ fn calcDecodedSizeExactUnsafe(source: []const u8, pad_char: u8) usize { test "base64" { - @setEvalBranchQuota(5000); + @setEvalBranchQuota(8000); testBase64() catch unreachable; comptime (testBase64() catch unreachable); } diff --git a/test/behavior.zig b/test/behavior.zig @@ -11,6 +11,7 @@ comptime { _ = @import("cases/bugs/394.zig"); _ = @import("cases/bugs/655.zig"); _ = @import("cases/bugs/656.zig"); + _ = @import("cases/bugs/828.zig"); _ = @import("cases/cast.zig"); _ = @import("cases/const_slice_child.zig"); _ = @import("cases/coroutines.zig"); diff --git a/test/cases/bugs/828.zig b/test/cases/bugs/828.zig @@ -0,0 +1,37 @@ +const CountBy = struct { + a: usize, + + const One = CountBy { + .a = 1, + }; + + pub fn counter(self: &const CountBy) Counter { + return Counter { + .i = 0, + }; + } +}; + +const Counter = struct { + i: usize, + + pub fn count(self: &Counter) bool { + self.i += 1; + return self.i <= 10; + } +}; + +fn constCount(comptime cb: &const CountBy, comptime unused: u32) void { + comptime { + var cnt = cb.counter(); + if(cnt.i != 0) @compileError("Counter instance reused!"); + while(cnt.count()){} + } +} + +test "comptime struct return should not return the same instance" { + //the first parameter must be passed by reference to trigger the bug + //a second parameter is required to trigger the bug + const ValA = constCount(&CountBy.One, 12); + const ValB = constCount(&CountBy.One, 15); +}