[cfe-dev] feature request: allowed duplicated case value in switch statement attribute, including ranges

K Concerns via cfe-dev cfe-dev at lists.llvm.org
Wed Dec 9 14:10:18 PST 2020


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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20201209/ae45d4ad/attachment.html>


More information about the cfe-dev mailing list