Known issues of FunC
The official smart contract language of TON Blockchain is Tolk. FunC is now a legacy language, with its compiler no longer maintained.
FunC pages will be moved down in the sidebar in mid-April 2026. Here is the preview of a possible future placement, right between "Blockchain foundations" and "Contribute" sections:


Learn how to migrate from FunC to Tolk.
Constant evaluation breaks function argument substitution
Removes division by zero exception
For the following operators and arithmetic functions, the compiler carries out optimizations during constant evaluation that removes the expected division by zero exception.
Multiplication/division built-ins
Issue page: #1678
For functions muldiv, muldivc and muldivr,
if any of their first two arguments is zero at compilation time, the compiler replaces the function call with 0, irrespective of the function's
third argument, i.e., the divisor. This means that the function calls get replaced by 0 even when the divisor is 0,
effectively removing the expected division by zero exception.
Examples:
;; All these produce 0, irrespective of divisor z,
;; even when z is 0.
muldiv(0, 1, z);
muldivc(1, 0, z);
muldivr(0, 1, z);Operators /, % combined with comparison operators
Issue pages: #1659, #1660, #1661, #1662.
The compiler simplifies the division / and modulo % operators when their left argument is 0,
but only when / and % are used in tandem with comparison operators like >=, >, ==, etc.
For example, the following expressions are not simplified to 0 at compile-time, which is the correct behavior:
0 / z; ;; NOT replaced by 0
0 % z; ;; NOT replaced by 0However, when comparison operators are used, the following expressions get simplified, irrespective of the value of z:
(0 % z) >= 0; ;; Replaced by true
(0 / z) >= 0; ;; Replaced by true
(0 % z) != 1; ;; Replaced by trueThis means that the FunC compiler removes the expected division by zero exception in the above examples when z = 0.
The following are further examples where the left operand of / and % is simplified to 0 by FunC, resulting in a final
expression that the compiler simplifies to true, irrespective of the value of z:
(~(-1) / z) >= 0;
((1 & (~ 1)) / z) >= 0;
((z & 0) / z) >= 0;
((z * 0) / z) >= 0;
(~(-1) % z) >= 0;
((1 & (~ 1)) % z) >= 0;
((z & 0) % z) >= 0;
((z * 0) % z) >= 0;
((x & 0) % z) == 1;
((x * 0) % z) == 1;
((-1 % z) % 1) <= 0;Removes integer overflow exception
Issue pages: #1656, #1657, #1658.
The following expressions should produce overflows for particular values of z,
but the FunC compiler simplifies them irrespective of z:
(0 & (- z)) <= 0; ;; Should overflow for z = -115792089237316195423570985008687907853269984665640564039457584007913129639936,
;; but simplified to true
(0 * (- z)) <= 0; ;; Should overflow for z = -115792089237316195423570985008687907853269984665640564039457584007913129639936,
;; but simplified to true
((z / -1) % 2) > -2; ;; Should overflow for z = -115792089237316195423570985008687907853269984665640564039457584007913129639936,
;; but simplified to trueThe following are further examples of expressions that should produce integer overflows at the indicated values,
but the FunC compiler simplifies them to true irrespective of the value of z:
(~(-1) & (-1 * z)) <= 0; ;; for z = MIN_INT.
((1 & (~ 1)) & (z / -1)) <= 0; ;; for z = MIN_INT.
((z & 0) & (z * 2)) <= 0; ;; for z = MAX_INT
((z * 0) & (z + 1)) <= 0; ;; for z = MAX_INT.
(~(-1) * (-1 * z)) <= 0; ;; for z = MIN_INT
((1 & (~ 1)) * (z / -1)) <= 0; ;; for z = MIN_INT
((z & 0) * (z * 2)) <= 0; ;; for z = MAX_INT
((z * 0) * (z + 1)) <= 0; ;; for z = MAX_INT
((-1 * z) % 2) > -2; ;; for z = MIN_INT
((- z) % 2) > -2; ;; for z = MIN_INT
((z * 2) % 2) > -2; ;; for z = MAX_INT
((z + 1) % 2) > -2; ;; for z = MAX_INTwhere MIN_INT = -115792089237316195423570985008687907853269984665640564039457584007913129639936 and
MAX_INT = 115792089237316195423570985008687907853269984665640564039457584007913129639935.
Incorrect results
Involving operator ~%
Issue Page: #1670
In the following code:
int calc(int x) {
return ((x ~% -3) <= 0);
}
int calc3(int x, int y, int z) {
return ((x ~% y) <= z);
}calling calc(1) produces -1. But calling calc3(1,-3,0) produces 0. But the expected behavior is calc(1) = calc3(1,-3,0), since calc is just a specialization of calc3.
The same happens with comparison operators: <=>, !=, and ==, i.e., the following expressions also produce differing results:
((x ~% -3) <=> 1)incalcfunction, and((x ~% y) <=> z)incal3function. Producescalc(1) = -1, andcalc3(1,-3,1) = 0.((x ~% -3) != 1)incalcfunction, and((x ~% y) != z)incal3function. Producescalc(1) = -1, andcalc3(1,-3,1) = 0.((x ~% -3) == 1)incalcfunction, and((x ~% y) == z)incal3function. Producescalc(1) = 0, andcalc3(1,-3,1) = -1.
Involving operator ^%
Issue Page: #1669
In the following code:
int calc(int x) {
return ((x ^% -2) <= 0);
}
int calc3(int x, int y, int z) {
return ((x ^% y) <= z);
}calling calc(1) produces -1. But calling calc3(1,-2,0) produces 0. But the expected behavior is calc(1) = calc3(1,-2,0), since calc is just a specialization of calc3.
The same happens with comparison operators: <=>, !=, and ==. The following expressions also produce differing results:
((x ^% -2) <=> 1)incalcfunction, and((x ^% y) <=> z)incal3function. Producescalc(1) = -1, andcalc3(1,-2,1) = 0.((x ^% -2) != 1)incalcfunction, and((x ^% y) != z)incal3function. Producescalc(1) = -1, andcalc3(1,-2,1) = 0.((x ^% -2) == 1)incalcfunction, and((x ^% y) == z)incal3function. Producescalc(1) = 0, andcalc3(1,-2,1) = -1.
Stack underflow in run_methodX functions
Issue Page: #1883.
The following code produces a stack underflow when run_method3 executes:
() test(int a, int b, int c) impure method_id(16384) {
~dump(a);
~dump(b);
~dump(c);
}
() recv_internal() impure {
run_method3(16384, 100, 200, 300);
}The expected behavior is that test function prints 100, 200, and 300 in the debug logs when run_method3 executes.
The functions run_method0, run_method1, and run_method2 have similar problems with stack underflow.
FunC does not throw on 1024 bits long slice constant creation with s literal
Issue page: #1153.
The following is successfully compiled:
const slice s = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"s;
() main () {
~dump(s);
}But the compiler should have thrown a compilation error due to the string being too long.
FunC ignores argument order when calling built-ins or asm functions via variables
Page issue: #1681.
;; Correct: directly calls built-in, respects ret_order
(int, int) correctBuiltin(int a, int b) {
return moddiv(a, b);
}
;; Incorrect: calling built-in via variable, ignores ret_order
(int, int) incorrectBuiltin(int a, int b) {
var f = moddiv;
return f(a, b);
}
;; Define the asm function with explicit ret_order
(int, int) myAsm(int a, int b) asm(-> 1 0) "SWAP";
;; Correct: directly calls asm function with explicit ret_order
(int, int) correctAsm(int a, int b) {
return myAsm(a, b);
}
;; Incorrect: calls asm function via variable, ignores ret_order
(int, int) incorrectAsm(int a, int b) {
var f = myAsm;
return f(a, b);
}
() main () {
~dump([correctBuiltin(5, 1)]); ;; [0 5] Correct
~dump([incorrectBuiltin(5, 1)]); ;; [5 0] Incorrect
~dump([correctAsm(5, 1)]); ;; [5 1] Correct
~dump([incorrectAsm(5, 1)]); ;; [1 5] Incorrect
}FunC crashes with fatal assertion when tensor exceeds 254 elements
Issue Page: 1682
The compiler crashes with a fatal internal assertion if a tensor exceeds 254 elements, instead of a proper user-facing error.
Example:
() main() {
var x = (
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
);
}which crashes with message:
fatal: Assertion failed at analyzer.cpp:46: k <= 254 && n <= 0x7fff00Last updated on