[Bug c++/87951] New: GCC warns about reaching end of non-void function when all switch is completely handled

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87951] New: GCC warns about reaching end of non-void function when all switch is completely handled

brooks at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87951

            Bug ID: 87951
           Summary: GCC warns about reaching end of non-void function when
                    all switch is completely handled
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: vlovich at gmail dot com
  Target Milestone: ---

If a function has a single switch statement that handles all enum values &
returns a value GCC will warn about the function not returning a value whereas
clang does not.  GCC requires an explicit __builtin_unreachable() annotation
after the switch. As of C++17 it seems to now be undefined behaviour rather
than unspecified behaviour for an enum to have a value that's not enumerated.

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1766

> cat test.c

enum Enum {
  A,
  B,
};

int CoverMyBases(enum Enum x) {
        switch (x) {
                case A:
                        return 1;
                case B:
                        return 0;
        }
}

int main(int argc, const char **argv) {
        CoverMyBases(A);
        CoverMyBases(B);
        return 0;
}

> g++-8 -Wall --std=c++17 test.c

test.c: In function 'CoverMyBases':
test.c:16:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^

> clang++ -std=c++17 -Wall test.c

NOTE: Clang never warns about this even prior to C++17 or in C either.
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87951] GCC warns about reaching end of non-void function when all switch is completely handled

brooks at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87951

Martin Liška <marxin at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
   Last reconfirmed|                            |2018-11-9
                 CC|                            |jason at gcc dot gnu.org,
                   |                            |marxin at gcc dot gnu.org,
                   |                            |redi at gcc dot gnu.org
           See Also|                            |https://gcc.gnu.org/bugzill
                   |                            |a/show_bug.cgi?id=87950

--- Comment #1 from Martin Liška <marxin at gcc dot gnu.org> ---
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1766
>

Can you please Jason and Jonathan comment about it? Can we strengthen behavior?
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87951] GCC warns about reaching end of non-void function when all switch is completely handled

brooks at gcc dot gnu.org
In reply to this post by brooks at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87951

--- Comment #2 from Martin Liška <marxin at gcc dot gnu.org> ---
One more comment here. I do cooperate with our openSUSE maintainer of Chromium
package and they have quite some of these warnings when building with GCC. I
told him he can strengthen behavior with -fstrict-enums option. Once we did
that the package crashes during build.
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87951] GCC warns about reaching end of non-void function when all switch is completely handled

brooks at gcc dot gnu.org
In reply to this post by brooks at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87951

--- Comment #3 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Vitali from comment #0)
> If a function has a single switch statement that handles all enum values &
> returns a value GCC will warn about the function not returning a value
> whereas clang does not.  GCC requires an explicit __builtin_unreachable()
> annotation after the switch. As of C++17 it seems to now be undefined
> behaviour rather than unspecified behaviour for an enum to have a value
> that's not enumerated.

No, that's not what the defect report says. I wish this myth would die.

Outside the range of the enumerated values does not mean not enumerated.
Given enum E { e0=0, e10=7 } there is nothing undefined about E(1) or E(4).

> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1766
>
> > cat test.c
>
> enum Enum {
>   A,
>   B,
> };
>
> int CoverMyBases(enum Enum x) {
> switch (x) {
> case A:
> return 1;
> case B:
> return 0;
> }
> }
>
> int main(int argc, const char **argv) {
> CoverMyBases(A);
> CoverMyBases(B);
> return 0;
> }
>
> > g++-8 -Wall --std=c++17 test.c
>
> test.c: In function 'CoverMyBases':
> test.c:16:1: warning: control reaches end of non-void function
> [-Wreturn-type]
>  }
>  ^

This is what -fstrict-enums is for.
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87951] GCC warns about reaching end of non-void function when all switch is completely handled

brooks at gcc dot gnu.org
In reply to this post by brooks at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87951

--- Comment #4 from Vitali <vlovich at gmail dot com> ---
Is there a way to annotate a specific enum as strict?
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87951] GCC warns about reaching end of non-void function when all switch is completely handled

brooks at gcc dot gnu.org
In reply to this post by brooks at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87951

--- Comment #5 from Vitali <vlovich at gmail dot com> ---
Jonathan, I think the defect report here does actually apply to this example. I
agree the argument could be made that if there's gaps in the enum values that
it's arguable that the current GCC behaviour is standards compliant (clearly
clang & GCC disagree on this for both C & C++ so unclear who's right or wrong
in their interpretation of what's allowed).

However, in the example posted this is a "dense" enum. There's no integer value
possible that's not outside the range & yet GCC still continues to treat that
as a possibility & thus missing optimization opportunities & generating
false-positive warnings.
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87951] GCC warns about reaching end of non-void function when all switch is completely handled

brooks at gcc dot gnu.org
In reply to this post by brooks at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87951

--- Comment #6 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Vitali from comment #5)
> Jonathan, I think the defect report here does actually apply to this
> example.

I didn't say otherwise.

> I agree the argument could be made that if there's gaps in the enum
> values that it's arguable that the current GCC behaviour is standards
> compliant (clearly clang & GCC disagree on this for both C & C++ so unclear
> who's right or wrong in their interpretation of what's allowed).

No, it has nothing to do with "gaps" in the enum. This is a myth.

All that matters is the range of representable values, which (for an
enumeration without a fixed underlying type) depends on the number of bits
required to represent the minimum and maximum enumerator values. It doesn't
make any difference whatsoever whether there are "gaps" between those minimum
and maximum
values.

> However, in the example posted this is a "dense" enum.

What matters is that all the values of the enum can be represented in a single
bit, and so the only valid values are 0 and 1, which happen to have
enumerators. But the only valid values would still be 0 and 1 if your enum was
defined as
enum Enum { B=1 }; and so a switch that failed to handle the possibility of
Enum(0) would be wrong (even with -fstrict-enums)

The mental model of "dense" vs "gaps" is WRONG.

> There's no integer
> value possible that's not outside the range & yet GCC still continues to
> treat that as a possibility & thus missing optimization opportunities &
> generating false-positive warnings.

Yes, that's what -fstrict-enums is for.

The default (without -fstrict-enums) assumes most code is buggy and doesn't
follow the rules. If you do not use values outside the valid range of values
for the enumeration, use -fstrict-enums.

I can see some value in the suggestion to annotate a specific enumeration type
as strict, but that might not be the right solution. What matters is how the
enumeration type is used (whether invalid values are ever created) and that
isn't something you can guarantee when the enum is declared.

You *can* annotate the uses of a specific enum, but telling the compiler that
no other values will ever be used in the switch, by adding:

  default:
    __builtin_unreachable();