feature request: allowed duplicated case value in switch statement attribute, including ranges

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

feature request: allowed duplicated case value in switch statement attribute, including ranges

Deep Majumder via cfe-dev
Normally, inside switch statements duplicate case values are disallowed.

For instance, the following code

switch(mytype)
{
  default:
  case MY_DUPLICATED_DEFINE_OR_ENUM:
  case 1:  //error, 1 shadows above if MY_DUPLICATED_DEFINE_OR_ENUM also ==1
  break;
}

yields an error message similar to

error: duplicate case value: '1' and 'MY_DUPLICATED_DEFINE_OR_ENUM' both equal '1'
      case MY_DUPLICATED_DEFINE_OR_ENUM:
note: previous case defined here

In this example, the duplicated error reveals almost-certainly erroneous code.

However, clang and other compiles like gcc support case ranges.

switch(mychar)
{
  case '!' ... '~': return my_isprint_string(mychar);
}

But if you want to add an exception for say the quote character '"', you must instead split the ranges. So

switch(mychar)
{
  case '!' ... ('"'-1)
  case ('"'+1) ... '~':
    return my_isprint_string(mychar);
  case '"': return "\\\"";  // escape quote
}

instead of

switch(mychar)
{
  case '"': return "\\\""; [[clang::badly_named_allow_duplicate_case]]
  case '!' ... '~': return my_isprint_string(mychar);
}

This simple example illustrates the basic problem. When you have multiple intersecting ranges, the problem becomes exacerbated.

Here's a slightly more complicated example:

// find width in bits
switch(myint64_t)
{
  // this won't compile
  case INT8_MIN ... INT8_MAX: return 8;
  case INT16_MIN ... INT16_MAX: return 16;
  case INT32_MIN ... INT32_MAX: return 32;
}

Fixing the above, which would be natural with duplicate labels, requires splitting the cases into 5 ranges, each dependent on the values of the other.

switch(myint64_t)
{
  case INT8_MIN ... INT8_MAX: return 8;
  case INT16_MIN ... INT8_MIN - 1: return: 16;
  case INT8_MAX + 1 ... INT16_MAX: return 16;
  case INT32_MIN ... INT16_MIN - 1: return 32;
  case INT16MAX + 1 .. INT32_MAX: return 32;
}

You can quickly see how interval math becomes more complicated. This is far less legible. In practice there are many more intervals to handle.

Allowing duplicate cases should be straightforward at the compiler level, however. The same methods that detect duplicates can be used to choose which duplicated case is executed. It doesn't matter which case statement, the first or the last, is considered to override so long as it is consistently applied.

This could be added either as an attribute on the switch or as an attribute on the individual cases. Something like "[[clang::badly_named_allow_duplicate]]" or "__attribute__((badly_named_allow_duplicate))"

Kevin Lawler

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev