GCC issues -Wtype-limits warnings for relational expressions that either cannot be true or cannot be false due to the limits of the type of one of their operands. This seems to work except for operands of type int where GCC fails to issue any warnings. $ cat u.c && gcc -S -Wall -Wextra -Wpedantic u.c int fchar (signed char x) { if (x <= __SCHAR_MAX__) // -Wtype-limits (good) return 1; if (x > __SCHAR_MAX__) // -Wtype-limits (good) return 1; return 0; } int fshrt (short x) { if (x <= __SHRT_MAX__) // -Wtype-limits (good) return 1; if (x > __SHRT_MAX__) // -Wtype-limits (good) return 1; return 0; } int fint (int x) { if (x <= __INT_MAX__) // missing -Wtype-limits return 1; if (x > __INT_MAX__) // missing -Wtype-limits return 1; return 0; } int flong (int x) { if (x <= __LONG_MAX__) // -Wtype-limits (good) return 1; if (x > __LONG_MAX__) // -Wtype-limits (good) return 1; return 0; } u.c: In function ‘fchar’: u.c:3:9: warning: comparison is always true due to limited range of data type [-Wtype-limits] 3 | if (x <= __SCHAR_MAX__) // -Wtype-limits (good) | ^~ u.c:6:9: warning: comparison is always false due to limited range of data type [-Wtype-limits] 6 | if (x > __SCHAR_MAX__) // -Wtype-limits (good) | ^ u.c: In function ‘fshrt’: u.c:14:9: warning: comparison is always true due to limited range of data type [-Wtype-limits] 14 | if (x <= __SHRT_MAX__) // -Wtype-limits (good) | ^~ u.c:17:9: warning: comparison is always false due to limited range of data type [-Wtype-limits] 17 | if (x > __SHRT_MAX__) // -Wtype-limits (good) | ^ u.c: In function ‘flong’: u.c:37:9: warning: comparison is always true due to limited range of data type [-Wtype-limits] 37 | if (x <= __LONG_MAX__) // -Wtype-limits (good) | ^~ u.c:40:9: warning: comparison is always false due to limited range of data type [-Wtype-limits] 40 | if (x > __LONG_MAX__) // -Wtype-limits (good) | ^
This never seems to have worked. Interestingly, Clang has the same bug.
In ILP32 it doesn't work for long either.
The problem is in shorten_compare() in c-common.c which deals with these cases. The comment above the block that handles this has this to say just above the conditional that guards the code. The conditional fails in the fint case because both operands of the inequality have the same precision: /* If comparing an integer against a constant more bits wide, maybe we can deduce a value of 1 or 0 independent of the data. Or else truncate the constant now rather than extend the variable at run time. This is only interesting if the constant is the wider arg. Also, it is not safe if the constant is unsigned and the variable arg is signed, since in this case the variable would be sign-extended and then regarded as unsigned. Our technique fails in this case because the lowest/highest possible unsigned results don't follow naturally from the lowest/highest possible values of the variable operand. For just EQ_EXPR and NE_EXPR there is another technique that could be used: see if the constant can be faithfully represented in the other operand's type, by truncating it and reextending it and see if that preserves the constant's value. */ if (!real1 && !real2 && TREE_CODE (TREE_TYPE (primop0)) != FIXED_POINT_TYPE && TREE_CODE (primop1) == INTEGER_CST && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)) { Eventually, after the function returns the inequality expression without a warning, c_parser_condition() calls c_fully_fold() on it which folds it into a constant, without a warning.
(In reply to Martin Sebor from comment #3) > Eventually, after the function returns the inequality expression without a > warning, c_parser_condition() calls c_fully_fold() on it which folds it into > a constant, without a warning. Happened to notice this PR when trying to answer the question [1]. The part doing the folding is from match.pd. /* Non-equality compare simplifications from fold_binary */ (for cmp (lt gt le ge) /* Comparisons with the highest or lowest possible integer of the specified precision will have known values. */ (simplify (cmp (convert?@2 @0) uniform_integer_cst_p@1) ... (if (wi::to_wide (cst) == max) (switch (if (cmp == GT_EXPR) { constant_boolean_node (false, type); }) (if (cmp == GE_EXPR) (eq @2 @1)) (if (cmp == LE_EXPR) { constant_boolean_node (true, type); }) I noticed there are some warning support in match.pd like fold_overflow_warning. Not sure whether we can add the similar supports there. Probably hard to get LOC? [1] https://gcc.gnu.org/pipermail/gcc-help/2021-January/139755.html