web-dev-qa-db-fra.com

GCC 7, -Avertissements de chute implicite, et moyen portable de les effacer?

Nous interceptons des avertissements de GCC 7 pour une chute implicite dans une instruction switch. Auparavant, nous les avons effacés sous Clang (c'est la raison du commentaire ci-dessous):

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:
   ^~~~

Le manuel GCC indique d'utiliser __attribute__ ((fallthrough)), mais ce n'est pas portable. Le manuel indique également "... il est également possible d'ajouter un commentaire de substitution pour faire taire l'avertissement" , mais il ne propose que FALLTHRU (est-ce vraiment le seul choix?):

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

Existe-t-il un moyen portable de supprimer la chute grâce aux avertissements pour Clang et GCC? Si oui, alors qu'est-ce que c'est?

29
jww

GCC attend le commentaire du marqueur sur sa propre ligne, comme ceci:

  m_state = BODY;
  // fall through
case BODY:

Le marqueur doit également se placer juste avant l'étiquette case; il ne peut y avoir de contreventement intermédiaire }.

fall through fait partie des marqueurs reconnus par GCC. Ce n'est pas seulement FALLTHRU. Pour une liste complète, consultez la documentation du -Wimplicit-fallthrough option . Voir aussi ceci publication sur le blog des développeurs Red Hat .

(Cela devrait également être compatible avec Clang, bien que je ne puisse pas obtenir le tronc actuel (r308163) pour émettre un avertissement de basculement pour vérifier cela.)

Notez que la suppression de l'avertissement avec des commentaires de marqueur ne fonctionne que si le compilateur voit réellement le commentaire. Si le préprocesseur s'exécute séparément, il doit être chargé de conserver les commentaires, comme avec le -C option de GCC ). Par exemple, pour éviter les avertissements parasites avec ccache , vous devez spécifier le -C flag lors de la compilation, ou, avec les versions récentes de ccache, utilisez le keep_comments_cpp option.

31
Florian Weimer

C++ 17 [[fallthrough]]

Exemple:

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

Compiler avec:

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

Si vous supprimez le [[fallthrough]];, Le CCG met en garde:

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:
         ^~~~

Notez également à partir de l'exemple que l'avertissement ne se produit que si vous tombez entre deux cas: la dernière instruction case (case 1 ici) ne génère aucun avertissement même s'il n'a pas break.

Les constructions suivantes ne génèrent pas non plus l'avertissement:

#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;
    }
}

Nous pouvons voir dans la dernière que GCC examine toutes les branches possibles et avertit si aucune d'entre elles n'a [[fallthrough]]; ou break ou return.

Vous pouvez également vérifier la disponibilité des fonctionnalités avec des macros comme dans cet extrait inspiré de GEM5 :

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

Voir aussi: https://en.cppreference.com/w/cpp/language/attributes/fallthrough

Testé sur GCC 7.4.0, Ubuntu 18.04.

Voir aussi

Version C de cette question: GCC 7, -Wimplicit-fallthrough warnings, and portable way to clear them?

Solution Clean C:

int r(int a) {
    switch(a) {
    case 0:
        a += 3;
    case 1:
        a += 2;
    default:
        a += a;
    }
    return a;
}

devient:

int h(int a) {
    switch(a) {
    case 0:
        a += 3;
        goto one;
    one:
    case 1:
        a += 2;
        goto others;
    others:
    default:
        a += a;
    }
    return a;
}
0
MCCCS