2

I have a piece of code of the following form:

typedef enum {A=1,B} EnumType;

int foo (EnumType x)
{
  int r;
  switch (x) {
    case A:
      r = 1;
      break;
    case B:
      r = 2;
      break;
      /*
    default:
      r = -1;
      break;
      */
  }
  return r;
}

I compile with GCC 6.3.0 and receive a warning:

$ gcc --version
gcc (MacPorts gcc6 6.3.0_2) 6.3.0
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ gcc -c -Wall -O1 test.c
test.c: In function 'foo':
test.c:20:10: warning: 'r' may be used uninitialized in this function [-Wmaybe-uninitialized]
   return r;
          ^

The code seems safe to me, and indeed there is some discussion of GCC producing false positives with this warning.

Is this a spurious warning?

More relevant information:

  • Adding the commented-out default: block resolves the warning
  • The warning does not appear with -O0
Patrick Sanan
  • 2,375
  • 1
  • 23
  • 25
  • 1
    If you know for 100% that x will never have a value you didn't provide a case for, you could add `default: __builtin_unreachable();` as a hint for the compiler. See [__builtin_unreachable()](https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-_005f_005fbuiltin_005funreachable) for more info. – ssbssa Aug 16 '17 at 23:55

2 Answers2

5

This warning is entirely correct, because an enum type doesn't restrict the possible values to the members defined in this enum -- it can instead hold any value of the underlying integer type. So without a default branch in your switch, you could indeed use r uninitialized with the code you show.

I can reproduce the warning missing with gcc and -O0 with the exact code shown in the question, so this looks to me like a bug in gcc. The warning should be given regardless of the optimization level.

  • Why would this warning not appear with `-O0`, then? – Patrick Sanan Jul 31 '17 at 07:12
  • 4
    This may be a bug. "Invalid" `enum` values are possible regardless of the optimization level. –  Jul 31 '17 at 07:13
  • @Felix Palmen it is not a bug. It is intentional - with switched on optimisation some of the statements can be optimised out. That that discussion took place 10-12 years ago on the gnu discussion lists. See in my answer – 0___________ Jul 31 '17 at 07:44
  • It was long discussion how to handle this UB. https://godbolt.org/g/TDUhN7 There is no way to even check if x has a valid value as compiler knows if it not has it is an UB. So warnings are issued - in this case this one – 0___________ Jul 31 '17 at 07:52
  • @PeterJ there's no check for a "valid" value defined in C. So if only optimizing out something actually causes `gcc` to *notice* this problem, it's an explanation but *still* a bug. The warning should be there in any case *for the code shown in the question*. –  Jul 31 '17 at 07:53
  • Not in the C - **in the code**. See my examples - when optimising there is no way to check if the value is outside the permitted values – 0___________ Jul 31 '17 at 07:55
  • You don't seem to get the simple fact that the code shown possibly uses `r` uninitialized. A missing warning about this is a bug when `gcc` promises to warn about these cases. There's no use arguing about that. –  Jul 31 '17 at 07:56
  • @Felix Palmen but it an result of an UB, – 0___________ Jul 31 '17 at 07:58
  • @Felix Palmen and even if you a very careful coder and always check for invalid values - in this case you cant as all your code will be optimised out https://godbolt.org/g/TDUhN7 – 0___________ Jul 31 '17 at 08:00
  • 2
    **It doesn't matter**. The code has a possibility for UB, the warning is supposed to warn about this, and **not** emitting the warning for `-O0` is a bug. –  Jul 31 '17 at 08:01
  • @Felix Palmen most compilers do not care about this UB at all and do not emit the warnings. Are they all buggy? – 0___________ Jul 31 '17 at 08:05
  • @PeterJ are you trying to troll here? `gcc` **has** this warning, and it's obviously buggy. EOD. –  Jul 31 '17 at 08:07
2

It is easy to figure out: there are possible program paths where r will be returned uninitialised. So you got the warning. Enum is just the int so you have a lots possible cases.

Enums are not checked runtime against the values.

About the second part of the question. It is intentional as any level of optimisation may (and in this case will remove the code if the values of the enum type are illegal - compiler assumes that no other values are possible)

https://godbolt.org/g/S9XE3d

This case is most interesting: https://godbolt.org/g/TDUhN7

You may think that you have checked against illegal values. But the compiler has stripped the code out :)

BTW - interesting why my answer was downvoted

0___________
  • 60,014
  • 4
  • 34
  • 74
  • I'm downvoting it because it's *plain wrong* now after the edit. Optimizations have *nothing* to do with the fact that the code in question exhibits possible UB. Remove that nonsense and I'll happily retract my vote. –  Jul 31 '17 at 08:27
  • No, I downvote *wrong* answers. Warnings *should* never depend on optimizations. With `gcc`, *some* of them unfortunately do, but in that case, they're [documented](https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html) to require the optimizer for better precision. `-Wmaybe-uninitialized` isn't one of them, as it's by its definition easy to spot just in the source code. You're on a wrong path here. –  Jul 31 '17 at 09:00
  • @FelixPalmen, I'm afraid any implementation is permitted to warn the user or not, without exhibiting UB in any way. Warnings are implementation dependent, and the standard compliance doesn't get compromised when an implementation decides not to emit a warning. The explanation of PeterJ is perfectly valid and consistent with the implementation of gcc, I'm afraid. In this case, due to possible UB **in the compiled program** we are in a case of compiling an erroneous program, and the compiler is free to give a warning, and compile to a final working program. Or not. – Luis Colorado Aug 01 '17 at 09:49
  • @LuisColorado of course warning about this is completely optional, and many compilers don't provide a warning. The point is: `gcc` **does** provide one and, according to the `gcc` documentation, it doesn't depend on the optimization level. So if **this** warning is missing with `gcc` and `-O0`, it's a `gcc` bug (or at least a wrong documentation). –  Aug 01 '17 at 09:50
  • @Felix Palmen - report it.And let us know that the answer is. – 0___________ Aug 01 '17 at 09:51
  • @PeterJ I'm not particularly interested in getting it fixed, so why should I. But the documentation is clear. Warnings should ideally *never* depend on the optimization level, and in cases where they do with `gcc`, it's explicitly documented. –  Aug 01 '17 at 09:54
  • @FelixPalmen, I'll accept it as a wrong documentation. Once I got what is supposed to be a gcc bug, as it joined in the assembler output two assembler statements in same line. And this made gas (gnu assembler) to fail with a syntax error. When I reported this to gcc guys, they answered this was not a bug, but a feature, so I'm afraid you'll get the same kind of response. – Luis Colorado Aug 01 '17 at 10:00
  • ...The final case was that with a different gas version it worked... so some compiler production (which was indeed bad assembler code) was corrected **in the assembler**, and not in the compiler. – Luis Colorado Aug 01 '17 at 10:03
  • @Felix Palmen opinions, opinions - mine can be same good or wrong as yours. But your ones are always right? Aren't they? `but something as wrong as this just needs to be judged` – 0___________ Aug 01 '17 at 10:05
  • @PeterJ it's not an opinion but can be proven from existing sources. And there's even more wrong in your answer: The compiler isn't allowed to *unconditionally* optimize away any code handling other values than the `enum` constants, because the underlying type of the `enum` can be implicitly converted to the `enum`. This allows handling of *flag style* `enums`, for example. –  Aug 01 '17 at 10:14
  • @Felix Palmen - `can be`?. No, you can convert it but there is no implicit conversion except for the arithmetic operations. Underlying `enum` type can be either `char` or `unsigned int` and the choice is left to the implementation. Compiler can assume that the values of the `enum` object have to exactly as in definition. Programmer can convert it to the underlying type (or any other). – 0___________ Aug 01 '17 at 10:30
  • "*Underlying enum type can be either char or unsigned int and the choice is left to the implementation*" <- this is the **only** part of your comment that's correct. –  Aug 01 '17 at 10:32