Consider the following example: int foo() { return 1 / static_cast<double>(0); } With -Wall -Wextra there is no warning about an undefined behavior ([conv.fpint] p1 "The behavior is undefined if the truncated value cannot be represented in the destination type.") Please add a warning Godbolt playground: https://godbolt.org/z/cMYo6xPaY
Clang warns with -Wconversion (which is not in -Wall -Wextra) <source>:2:14: warning: implicit conversion of out of range value from 'double' to 'int' is undefined [-Wfloat-overflow-conversion] 2 | return 1 / static_cast<double>(0); | ~~~~~~ ~~^~~~~~~~~~~~~~~~~~~~~~~~ 1 warning generated.
(In reply to Antony Polukhin from comment #0) > Consider the following example: > > int foo() { > return 1 / static_cast<double>(0); > } > > > With -Wall -Wextra there is no warning about an undefined behavior > ([conv.fpint] p1 "The behavior is undefined if the truncated value cannot be > represented in the destination type.") > > Please add a warning > > Godbolt playground: https://godbolt.org/z/cMYo6xPaY I tried this example : int foo() { return 1 / 0; } int main() { return 0; } There is a warning : 119222.cc: In function ‘int foo()’: 119222.cc:2:14: warning: 被零除(divide by zero)[-Wdiv-by-zero] 2 | return 1 / 0; | ~~^~~
That's a completely different example though. The bug is about conversion from double to int. 1/0 does not involve any floating-point types, it's just an undefined integer division. 1/static_cast<double>(0) is not undefined, it produces an infinite double value, it's only undefined when converted to int. Your example doesn't show that.
Maybe the bug is related to the code below: (in gcc/fold-const.cc :fold_binary_loc) case RDIV_EXPR: /* Don't touch a floating-point divide by zero unless the mode of the constant can represent infinity. */ if (TREE_CODE (arg1) == REAL_CST && !MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg1))) && real_zerop (arg1)) return NULL_TREE; /* (-A) / (-B) -> A / B */ if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1)) return fold_build2_loc (loc, RDIV_EXPR, type, TREE_OPERAND (arg0, 0), negate_expr (arg1)); if (TREE_CODE (arg1) == NEGATE_EXPR && negate_expr_p (arg0)) return fold_build2_loc (loc, RDIV_EXPR, type, negate_expr (arg0), TREE_OPERAND (arg1, 0)); These code uncovered that : There are two types of floating point numbers: support infinity and do not support infinity. And I tried to compile the testing code : int foo() { return 1/static_cast<double>(0) ; } int main() { double a = 1/static_cast<double>(0); return 0 ; } Howerver , there is no warning . SO is it feasible that these two situations can support infinity ?
And also see "constexpr.cc in "gcc/cp": the function "potential_constant_expression_1": if (integer_zerop (denom)) { if (flags & tf_error) constexpr_error (input_location, fundef_p, "division by zero is not a constant expression"); return false; } else { want_rval = true; return RECUR (TREE_OPERAND (t, 0), want_rval); } } Is this code missing a check for the "division by zero" condition in binary floating point operations? If my guess is correct , I want to fix the bug !
1.0/0.0 is well defined with IEEE floating point to be defined as infinite. Warning about that is not right. What this bug is asking for is the warning converting infinite or NaN to an integral type
... as I already tried to explain in comment 4.
I am sorry for my recklessness and carelessness! And thank you for your patient guidance. In gcc/convert.cc : func:convert_to_integer_1 : the case : case REAL_TYPE: if (sanitize_flags_p (SANITIZE_FLOAT_CAST) && current_function_decl != NULL_TREE) { expr = save_expr (expr); tree check = ubsan_instrument_float_cast (loc, type, expr); expr = build1 (FIX_TRUNC_EXPR, type, expr); if (check == NULL_TREE) return expr; return maybe_fold_build2_loc (dofold, loc, COMPOUND_EXPR, TREE_TYPE (expr), check, expr); } else return build1 (FIX_TRUNC_EXPR, type, expr); this case is about processing floating point numbers. But when I use gdb to figure out the run process of this case gdb --args ../objdir/gcc/cc1plus -Wall -Wextra 119222.cc However,The program is executed "return build1 (FIX_TRUNC_EXPR, type, expr); "directly . Breakpoint 2, convert_to_integer_1 (type=0x7ffff78285e8, expr=0x7ffff79bba28, dofold=false) at ../../gcc/gcc/convert.cc:934 934 if (sanitize_flags_p (SANITIZE_FLOAT_CAST) (gdb) s sanitize_flags_p (flag=flag@entry=65536, fn=0x7ffff79c1b00) at ../../gcc/gcc/asan.h:248 248 if (result_flags == 0) (gdb) s convert_to_integer_1 (type=0x7ffff78285e8, expr=0x7ffff79bba28, dofold=false) at ../../gcc/gcc/convert.cc:946 This indicates that the sanitization for detecting floating point conversions is not enabled.
Because you didn't compile with -fsanitize=float-cast-overflow If you use that option, then SANITIZE_FLOAT_CAST will be set. But that is about adding instrumentation to give runtime diagnostics. This bug is about compile-time warnings, which should be possible because the all values here are constants.
Emmmm , This is a bit complicated. But I think the problem must occur in the grammatical analysis or semantic analysis stage I would like to know in which file should the code for floating point (real number) type conversion be located during the compile-time? Based on this ,I want to pinpoint the root cause of the bug . I think I must solve the bug !
I know how this bug generate this time (100%)! This is because the funx conversion_warning (in c-family/c-warn.cc , the helper function for warnings_for_convert_and_check)lacks some checks when expr is of type double here is the curcial part about this bugu of conversion_warning: static bool conversion_warning (location_t loc, tree type, tree expr, tree result) { // type -> int , expr->1.0/0.0 result->(int)1.0/0.0 ..... switch (TREE_CODE (expr)) { case EQ_EXPR: case NE_EXPR: case LE_EXPR: case GE_EXPR: ..... case REAL_CST: case INTEGER_CST: ..... } return false ; } And warning_for_convert_and_check only responsible for the two situations below : if (TREE_CODE (expr) == INTEGER_CST && (TREE_CODE (type) == INTEGER_TYPE || TREE_CODE (type) == BITINT_TYPE || (TREE_CODE (type) == ENUMERAL_TYPE && TREE_CODE (ENUM_UNDERLYING_TYPE (type)) != BOOLEAN_TYPE)) && !int_fits_type_p (expr, type)) {....} else if ((TREE_CODE (result) == INTEGER_CST || TREE_CODE (result) == FIXED_CST) && TREE_OVERFLOW (result)) {.....} The rest of the situation is all handed over to the top function。 If you need more testimonies , I will give you !!!!!
When executing the conversion_warning function, if you do not add any of the three compilation options -Warn-conversion or -Warn_sign_conversion or -Warn-float-conversion, the function will return directly. This function is the key function for issuing warnings about type conversion during compilation. Therefore, if you need to issue a warning during type conversion, you must add one of the three options. On this basis, I have made some modifications to the conversion_warning function. Only in: switch (TREE_CODE (expr)) { case EQ_EXPR: case NE_EXPR: case LE_EXPR: ...... case RDIV_EXPR: /*Issue a warning about infinity conversion to int*/ if( TREE_CODE(type) == INTEGER_TYPE && TREE_CODE (TREE_OPERAND(expr,1)) == REAL_CST && real_zerop (TREE_OPERAND(expr,1))) warning_at(loc, OPT_Wfloat_conversion, "conversion from %qT to %qT changes infinity to maximum or minimum integer value", expr_type , type) ; arith_ops = 2; goto default_; Make the above modifications to case RDIV_EXPR Compile after modification: gwne@gwne-KLVG-XX:~/github_repo/gcc/test$ ../objdir/gcc/cc1plus -Wall -Wextra -Wfloat-conversion 119222.cc int main()119222.cc:4:14: warning: conversion from ‘double’ to ‘int’ changes infinity to maximum or minimum integer value [-Wfloat-conversion] 4 | int a = 1/static_cast<double>(0); | ~^~~~~~~~~~~~~~~~~~~~~~~ 119222.cc:4:9: warning: unused variable ‘a’ [-Wunused-variable] 4 | int a = 1/static_cast<double>(0); | ^
and I will send the patch at the same time
(In reply to Gwen Fu from comment #13) > warning_at(loc, OPT_Wfloat_conversion, > "conversion from %qT to %qT changes infinity to maximum or minimum integer > value", expr_type , type) ; The message could be improved, the conversion has undefined behaviour, so according to the C++ standard it could convert to any value, or crash the program, or anything else.
I am void under the gcc/c-family/c-warn.cc file warnings_for_convert_and_check (location_t loc, tree type, tree expr, tree result) function performs the following judgment and processing: /*"inifity to int" this operation belongs to FIX_TRUNC_EXPR*/ else if (TREE_CODE(result) == FIX_TRUNC_EXPR && TREE_CODE(exprtype) == REAL_TYPE) { bool warn_flag = false; tree dst = expr; /*Considering that it may be an assignment expression, expr may be a variable declaration.*/ if(TREE_CODE(dst) == VAR_DECL) dst = DECL_INITIAL(dst); /*This situation has not been found during the debugging process, but just in case, the judgment of this situation is still added*/ if (TREE_CODE(dst) == REAL_CST) { REAL_VALUE_TYPE value = TREE_REAL_CST(expr); bool is_inf = REAL_VALUE_ISINF(value); if (is_inf) warn_flag = true; } else if (TREE_CODE(dst) == RDIV_EXPR && TREE_CODE (TREE_OPERAND(dst, 1)) == REAL_CST && real_zerop (TREE_OPERAND(dst, 1))) warn_flag = true; /*After getting the initial value of the variable, the node type is FLOAT_EXPR*/ else if (TREE_CODE(dst) == FLOAT_EXPR) { tree op = dst; if(EXPR_P(TREE_OPERAND(op, 0))) op = TREE_OPERAND(op, 0) ; tree denominator = TREE_OPERAND(op, 1) ; if ((TREE_CODE(denominator) == INTEGER_CST && integer_zerop(denominator))) warn_flag = true; } if(warn_flag) warning_at (loc, 0, "Undefined behavior : conversion " "from %qT to %qT", expr, type); conversion_warning(loc , type , expr , result); } When performing "make -check-gcc", a series of Fail messages are displayed in the file gcc.dg/analyzer/data-model-1.c, but these messages did not appear before the source code was modified: FAIL: gcc.dg/analyzer/data-model-1.c (internal compiler error: Segmentation fault) FAIL: gcc.dg/analyzer/data-model-1.c (test for warnings, line 19) ....... FAIL: gcc.dg/analyzer/data-model-1.c (test for warnings, line 1015) FAIL: gcc.dg/analyzer/data-model-1.c (test for warnings, line 1016) FAIL: gcc.dg/analyzer/data-model-1.c (test for warnings, line 1028) FAIL: gcc.dg/analyzer/data-model-1.c (test for warnings, line 1029) FAIL: gcc.dg/analyzer/data-model-1.c (test for excess errors)
Created attachment 60895 [details] Other cases of this conversion, including assignment and some other use cases Initialization and assignment