Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCC 7, -Wimplicit-fallthrough warnings, and portable way to clear them?

We are catching warnings from GCC 7 for implicit fall through in a switch statement. Previously, we cleared them under Clang (that's the reason for the comment seen below):

g++ -DNDEBUG -g2 -O3 -std=c++17 -Wall -Wextra -fPIC -c authenc.cpp
asn.cpp: In member function ‘void EncodedObjectFilter::Put(const byte*, size_t)’:
asn.cpp:359:18: warning: this statement may fall through [-Wimplicit-fallthrough=]
    m_state = BODY;  // fall through
                  ^
asn.cpp:361:3: note: here
   case BODY:
   ^~~~

The GCC manual states to use __attribute__ ((fallthrough)), but its not portable. The manual also states "... it is also possible to add a fallthrough comment to silence the warning", but it only offer FALLTHRU (is this really the only choice?):

switch (cond)
  {
  case 1:
    bar (0);
    /* FALLTHRU */
  default:
    …
  }

Is there a portable way to clear the fall through warning for both Clang and GCC? If so, then what is it?

like image 322
jww Avatar asked Jul 16 '17 14:07

jww


People also ask

How do I stop a GCC warning?

To answer your question about disabling specific warnings in GCC, you can enable specific warnings in GCC with -Wxxxx and disable them with -Wno-xxxx. From the GCC Warning Options: You can request many specific warnings with options beginning -W , for example -Wimplicit to request warnings on implicit declarations.

How do I get rid of the unused variable warning?

Solution: If variable <variable_name> or function <function_name> is not used, it can be removed. If it is only used sometimes, you can use __attribute__((unused)) . This attribute suppresses these warnings.

What is a GCC warning?

Warnings are diagnostic messages that report constructions that are not inherently erroneous but that are risky or suggest there may have been an error. The following language-independent options do not enable specific warnings but control the kinds of diagnostics produced by GCC.


3 Answers

GCC expects the marker comment on its own line, like this:

  m_state = BODY;
  // fall through
case BODY:

The marker also has to come right before the case label; there cannot be an intervening closing brace }.

fall through is among the markers recognized by GCC. It's not just FALLTHRU. For a full list, see the documentation of the -Wimplicit-fallthrough option. Also see this posting on the Red Hat Developer blog.

C++17 adds a [[fallthrough]] attribute that can be used to suppress such warnings. Note the trailing semicolon:

  m_state = BODY;
  [[fallthrough]];
case BODY:

Clang supports -Wimplicit-fallthrough warnings, but does not enable them as part of -Wall or -Wextra. Clang does not recognize comment markers, so the attribute-based suppression has to be used for it (which currently means the non-standard __attribute__((fallthrough)) construct for the C front end).

Note that suppressing the warning with marker comments only works if the compiler actually sees the comment. If the preprocessor runs separately, it needs to be instructed to preserve comments, as with the -C option of GCC. For example, to avoid spurious warnings with ccache, you need to specify the -C flag when compiling, or, with recent versions of ccache, use the keep_comments_cpp option.

like image 166
Florian Weimer Avatar answered Sep 29 '22 09:09

Florian Weimer


C++17 [[fallthrough]]

Example:

int main(int argc, char **argv) {
    switch (argc) {
        case 0:
            argc = 1;
            [[fallthrough]];
        case 1:
            argc = 2;
    };
}

Compile with:

g++ -std=c++17 -Wimplicit-fallthrough main.cpp

If you remove the [[fallthrough]];, GCC warns:

main.cpp: In function ‘int main()’:
main.cpp:5:15: warning: this statement may fall through [-Wimplicit-fallthrough=]
             argc = 1;
             ~~^~~
main.cpp:6:9: note: here
         case 1:
         ^~~~

Also note from the example that the warning only happens if you fall beacross two cases: the last case statement (case 1 here) generates no warnings even though it has no break.

The following constructs don't generate the warning either:

#include <cstdlib>

[[noreturn]] void my_noreturn_func() {
    exit(1);
}

int main(int argc, char **argv) {
    // Erm, an actual break
    switch (argc) {
        case 0:
            argc = 1;
            break;
        case 1:
            argc = 2;
    }

    // Return also works.
    switch (argc) {
        case 0:
            argc = 1;
            return 0;
        case 1:
            argc = 2;
    }

    // noreturn functions are also work.
    // https://stackoverflow.com/questions/10538291/what-is-the-point-of-noreturn/47444782#47444782
    switch (argc) {
        case 0:
            argc = 1;
            my_noreturn_func();
        case 1:
            argc = 2;
    }

    // Empty case synonyms are fine.
    switch (argc) {
        case 0:
        case 1:
            argc = 2;
    }

    // Magic comment mentioned at:
    // https://stackoverflow.com/a/45137452/895245
    switch (argc) {
        case 0:
            argc = 1;
            // fall through
        case 1:
            argc = 2;
    }

    switch (argc) {
        // GCC extension for pre C++17.
        case 0:
            argc = 1;
            __attribute__ ((fallthrough));
        case 1:
            argc = 2;
    }

    switch (argc) {
        // GCC examines all braches.
        case 0:
            if (argv[0][0] == 'm') {
                [[fallthrough]];
            } else {
                return 0;
            }
        case 1:
            argc = 2;
    }
}

We can see from the last one that GCC examines all possible branches, and warns if any of them don't have [[fallthrough]]; or break or return.

You might also want to check for feature availability with macros as in this GEM5 inspired snippet:

#if defined __has_cpp_attribute
    #if __has_cpp_attribute(fallthrough)
        #define MY_FALLTHROUGH [[fallthrough]]
    #else
        #define MY_FALLTHROUGH
    #endif
#else
    #define MY_FALLTHROUGH
#endif

See also: https://en.cppreference.com/w/cpp/language/attributes/fallthrough

Tested on GCC 7.4.0, Ubuntu 18.04.

See also

C version of this question: How to do an explicit fall-through in C


Another example: The Linux kernel provides a fallthrough pseudo-keyword macro. Which can be used as:

switch (cond) {
case 1:
    foo();
    fallthrough;
case 2:
    bar();
    break;
default:
    baz();
}

In kernel v5.10 its implemented like this:

#if __has_attribute(__fallthrough__)
# define fallthrough                    __attribute__((__fallthrough__))
#else
# define fallthrough                    do {} while (0)  /* fallthrough */
#endif
like image 3
sergej Avatar answered Sep 29 '22 09:09

sergej