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?
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.
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;
}