mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 03:51:18 +00:00
Compile time fmod evaluates to 0 #1195
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
- Duplicate emit of expressions on negation would incorrectly compile negated macros.
|
||||
- Casting a slice address to its pointer type should not compile #1193.
|
||||
- Union is not properly zero-initialized with designated initializer #1194.
|
||||
- Compile time fmod evaluates to 0 #1195.
|
||||
|
||||
### Stdlib changes
|
||||
- Add 'zstr' variants for `string::new_format` / `string::tformat`.
|
||||
|
||||
@@ -2015,6 +2015,7 @@ Float float_sub(Float op1, Float op2);
|
||||
Float float_mul(Float op1, Float op2);
|
||||
Float float_div(Float op1, Float op2);
|
||||
Float float_neg(Float op);
|
||||
Float float_rem(Float op1, Float op2);
|
||||
Float float_from_string(const char *string, char **error);
|
||||
Float float_from_hex(const char *string, char **error);
|
||||
Int128 i128_from_double(double x);
|
||||
|
||||
@@ -85,6 +85,12 @@ Float float_div(Float op1, Float op2)
|
||||
return (Float){ op1.f / op2.f, op1.type };
|
||||
}
|
||||
|
||||
Float float_rem(Float op1, Float op2)
|
||||
{
|
||||
assert(op1.type == op2.type);
|
||||
return (Float){fmod(op1.f, op2.f), op1.type };
|
||||
}
|
||||
|
||||
Float float_neg(Float op)
|
||||
{
|
||||
op.f = -op.f;
|
||||
|
||||
@@ -5561,19 +5561,36 @@ static bool sema_expr_analyse_mod(SemaContext *context, Expr *expr, Expr *left,
|
||||
// 1. Analyse both sides and promote to a common type
|
||||
if (!sema_binary_analyse_arithmetic_subexpr(context, expr, NULL, false)) return false;
|
||||
|
||||
// 3. a % 0 is not valid, so detect it.
|
||||
if (expr_is_const(right) && int_is_zero(right->const_expr.ixx))
|
||||
Type *flat = type_flatten(left->type);
|
||||
if (type_is_float(flat))
|
||||
{
|
||||
SEMA_ERROR(right, "Cannot perform %% with a constant zero.");
|
||||
return false;
|
||||
}
|
||||
// 3. a % 0 is not valid, so detect it.
|
||||
if (expr_is_const(right) && right->const_expr.fxx.f == 0.0)
|
||||
{
|
||||
RETURN_SEMA_ERROR(right, "Cannot perform %% with a constant zero.");
|
||||
}
|
||||
|
||||
// 4. Constant fold
|
||||
if (expr_both_const(left, right) && sema_constant_fold_ops(left))
|
||||
// 4. Constant fold
|
||||
if (expr_both_const(left, right) && sema_constant_fold_ops(left))
|
||||
{
|
||||
expr_replace(expr, left);
|
||||
// 4a. Remember this is remainder.
|
||||
expr->const_expr.fxx = float_rem(left->const_expr.fxx, right->const_expr.fxx);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
expr_replace(expr, left);
|
||||
// 4a. Remember this is remainder.
|
||||
expr->const_expr.ixx = int_rem(left->const_expr.ixx, right->const_expr.ixx);
|
||||
assert(type_is_integer(flat));
|
||||
// 3. a % 0 is not valid, so detect it.
|
||||
if (expr_is_const(right) && int_is_zero(right->const_expr.ixx)) RETURN_SEMA_ERROR(right, "Cannot perform %% with a constant zero.");
|
||||
|
||||
// 4. Constant fold
|
||||
if (expr_both_const(left, right) && sema_constant_fold_ops(left))
|
||||
{
|
||||
expr_replace(expr, left);
|
||||
// 4a. Remember this is remainder.
|
||||
expr->const_expr.ixx = int_rem(left->const_expr.ixx, right->const_expr.ixx);
|
||||
}
|
||||
}
|
||||
|
||||
expr->type = type_add_optional(left->type, IS_OPTIONAL(right));
|
||||
|
||||
17
test/test_suite/compile_time/mod_ct.c3t
Normal file
17
test/test_suite/compile_time/mod_ct.c3t
Normal file
@@ -0,0 +1,17 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
fn int main()
|
||||
{
|
||||
double a = 4.5 % 5;
|
||||
double b = -4.5 % 5;
|
||||
int ai = 4 % 5;
|
||||
int bi = -4 % 5;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
store double 4.500000e+00, ptr %a, align 8
|
||||
store double -4.500000e+00, ptr %b, align 8
|
||||
store i32 4, ptr %ai, align 4
|
||||
store i32 -4, ptr %bi, align 4
|
||||
Reference in New Issue
Block a user