web-dev-qa-db-ja.com

GCC 7、-暗黙のフォールスルー警告、およびそれらをクリアするポータブルな方法?

Switchステートメントでの暗黙的なフォールスルーに関するGCC 7からの警告をキャッチしています。以前は、Clangでそれらをクリアしました(以下にコメントの理由があります):

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

GCCマニュアル__attribute__ ((fallthrough))を使用するように述べていますが、移植性はありません。また、マニュアルには "と記載されています。..警告を黙らせるためにフォールスルーコメントを追加することもできます"が、FALLTHRUのみを提供しています(これが本当に唯一の選択肢ですか?):

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

ClangとGCCの両方でフォールスルー警告をクリアするポータブルな方法はありますか?もしそうなら、それは何ですか?

29
jww

GCCは、次のように、マーカーコメントを独自の行に期待しています。

  m_state = BODY;
  // fall through
case BODY:

また、マーカーはcaseラベルの直前に来る必要があります。中間の閉じ中括弧}は存在できません。

fall throughは、GCCによって認識されるマーカーの1つです。 FALLTHRUだけではありません。完全なリストについては、 -Wimplicit-fallthroughオプション のドキュメントを参照してください。こちらもご覧ください Red Hat Developerブログに投稿

(これもClangと互換性があるはずですが、現在のトランク(r308163)でこれを確認するための切り替えフォールスルー警告を出すことはできません。)

マーカーコメントで警告を無視することは、コンパイラが実際にコメントを認識した場合にのみ機能することに注意してください。プリプロセッサが個別に実行される場合、GCCの -Cオプション )と同様に、コメントを保持するように指示する必要があります。たとえば、 ccache を使用した誤った警告を回避するには、コンパイル時に-Cフラグを指定するか、ccacheの最新バージョンではkeep_comments_cppオプションを使用する必要があります。

31
Florian Weimer

C++ 17 [[fallthrough]]

例:

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

コンパイル:

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

[[fallthrough]];を削除すると、GCCは警告します:

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

また、この例から、2つのケースにまたがった場合にのみ警告が発生することに注意してください。最後のcaseステートメント(ここではcase 1)は、breakがなくても警告を生成しません。

次の構成体も警告を生成しません。

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

最後の例から、GCCはすべての可能なブランチを調べ、それらのいずれかが[[fallthrough]];またはbreakまたはreturnを持たない場合に警告することがわかります。

この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

参照: https://en.cppreference.com/w/cpp/language/attributes/fallthrough

GCC 7.4.0、Ubuntu 18.04でテスト済み。

こちらもご覧ください

この質問のCバージョン: GCC 7、-Wimplicit-fallthrough warnings、およびそれらをクリアするポータブルな方法?

クリーンCソリューション:

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

になる:

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