Issue in -Wtautological-constant-out-of-range-compare?

Hi all,
I am seeing the -Wtautological-constant-out-of-range-compare warning for the first time.

With this Apple clang version:
$ clang --version
Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin13.0.0
Thread model: posix

In this program:
#include <stdio.h>

typedef enum o {
    O_1 = 0,
    O_2,
} o;

int main(int argc, char** argv) {
  enum o e1 = -1;

  if( e1 >= 2 ) {
    printf( "That's not right\n" );
  }

  printf("e1:%d\n",e1);

  return 0;
}

Compiled thus, I get the warning that my if test above will always evaluate as false:
$ clang -Wall -std=c89 t1.c
t1.c:11:10: warning: comparison of constant 2 with expression of type 'enum o'
      is always false [-Wtautological-constant-out-of-range-compare]
  if( e1 >= 2 ) {
      ~~ ^ ~
1 warning generated.

That is demonstrably untrue:
$ ./a.out
That's not right
e1:-1

Does this error also occur in the mainline clang? I am unsure whether to raise the issue with Apple or the clang developers.

Thanks,
Fred

I believe this does also happen in ToT Clang & there’s been some discussion (perhaps it’s on an internal Google bug, I forget) about the right thing to do here.

I think one of the issues is that your code isn’t guaranteed to behave that way - it’s possible for an implementation to map -1 onto one of the existing 0/1 bit values of the enum (the enum only needs to be one bit wide (obviously sizeof won’t reflect that, it still has to take at least a byte of storage)). Arguably, though, it’s still possibel on some implementations (including Clang) for it to have such a value…

The wording is tricky - between underlying types and ranges, etc, I don’t have it all perfectly straight in my head.

Thanks for confirming that this also happens in other clang branches.

In C an enumeration is defined as an enumeration constant and 6.4.4.3 of the draft C standard April 12, 2011 ISO/IEC 9899:201x I am looking at says:
An identifier declared as an enumeration constant has type int.

6.7.2.2 says:
Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined,128) but shall be capable of representing the values of all the members of the enumeration.

As long as it isn't forbidden to assign out-of-enumeration values to an enumeration I think that it is invalid to say that the comparison of any out of declared enumeration range value is guaranteed to be tautological - I have certainly seen lots of code that uses out of enumeration values to flag that a value is uninitialised etc. (no comment on how good the style is). Of course, code of that form would need to use values that are in the range of the implementation-defined type that is used to have a chance of being meaningful.

Thanks,
Fred

We shouldn’t be assuming that enum values are in range in C, only in C++ (and even there it’s controversial). Please file a PR.