V1087. Upper bound of case range is less than its lower bound. This case may be unreachable.
The analyzer detected a situation where the upper bound of range in the 'case' label is less than its lower bound. Perhaps, this is a typo, and the part of code may become unreachable.
The GCC and Clang compilers have the Case Ranges extension which allows you to specify a range of constant values instead of a single value for the 'case' label. Such a range will be similar to the sequence of 'case' labels, including boundary values:
switch (....)
{
case 1 ... 3:
// Do something
break;
}
// Similar to the previous 'switch' statement
switch (....)
{
case 1:
case 2:
case 3:
// Do something
break;
}
However, if the upper bound of the specified range is less than its lower bound, this range will be treated as empty. If you specify such a range, then during the condition check control can never be passed to the label. Therefore, the code branch can become unreachable.
Look at the synthetic example:
void foo(int i)
{
switch (i)
{
case 1 ... 3:
// First case
break;
case 6 ... 4: // <=
// Second case
break;
case 7 ... 9:
// Third case
break;
}
}
In the second label, the '4' and '6' constants were mixed up in places, which is why control will never be transferred to the label. Correct example:
void foo(int i)
{
switch (i)
{
case 1 ... 3:
// First case
break;
case 4 ... 6: // <=
// Second case
break;
case 7 ... 9:
// Third case
break;
}
}
An error of this kind can occur when named constants or values returned by 'constexpr' functions are incorrectly used. Look at the synthetic example:
constexpr int for_yourself_min() noexcept { return 1; }
constexpr int for_yourself_max() noexcept { return 3; }
constexpr int for_neighbors_min() noexcept { return 4; }
constexpr int for_neighbors_max() noexcept { return 6; }
void distributeCats(int count)
{
switch (count)
{
case for_yourself_min() ... for_yourself_max():
// Keep for yourself
break;
case for_neighbors_max() ... for_neighbors_min(): // <=
// Give cats to neighbors
break;
default:
// Give cats to a cattery
break;
}
}
There's a typo in the second label. Because of this, function calls are mixed up in places, and control will never be passed to the label. Correct example:
constexpr int for_yourself_min() noexcept { return 1; }
constexpr int for_yourself_max() noexcept { return 3; }
constexpr int for_neighbors_min() noexcept { return 4; }
constexpr int for_neighbors_max() noexcept { return 6; }
void distributeCats(int count)
{
switch (count)
{
case for_yourself_min() ... for_yourself_max():
// Keep for yourself
break;
case for_neighbors_min() ... for_neighbors_max(): // <=
// Give cats to neighbors
break;
default:
// Give cats to a cattery
break;
}
}
However, incorrect range doesn't always lead to unreachable code. If there is no 'break' in the 'case' label above, then after its branch is executed, control will be passed to 'case' with an empty range. Synthetic example:
void foo(int i)
{
switch (i)
{
case 0: // no break
case 3 ... 1:
// First and second case
break;
case 4:
// Third case
default:
// Do something
}
}
Despite the code is reachable, an empty range looks strange and meaningless. This may be a typo or incorrect macro expansion. Therefore, the absence of 'break' in the label above is not an exception for the diagnostic, and the analyzer will issue a warning.
This diagnostic is classified as: