世界を動かす技術を、日本語で。

GCC 16がリリースされました

概要

  • GCC 16 の主な新機能や変更点のまとめ
  • Solaris 向けの非互換変更点への注意喚起
  • 最適化・ベクトル化 の強化やドキュメントの改良
  • C++20 がデフォルト標準、C++23/26の一部機能も実装
  • OpenMP/OpenACC/Ada/Fortran など各言語の拡張と改善

GCC 16の主な変更点・新機能

  • int8_t などの型がSolarisで signed char に変更、C99準拠のための非互換対応
  • -pthread オプションがSolarisで _REENTRANT を自動定義しなくなった
  • -fdiagnostics-format=json 形式が削除、機械可読な診断は SARIF 利用推奨

最適化・ベクトル化の改善

  • Link-Time Optimizationtoplevel asm 文をより適切に処理
  • Speculative devirtualization が一般的な間接関数呼び出しに対応、複数ターゲットの推測も可能
  • ベクトル化 がループ内の並列性やカウント不能ループにも対応
  • アラインメントの剥離(peeling) やマスキングによる柔軟なループ最適化
  • 早期breakを含むループ で効率的なコード生成

ドキュメントの刷新

  • コマンドオプション属性 のドキュメントが整理・近代化
  • パラメータ・オプション仕様ファイル の説明をGCC内部マニュアルへ移動
  • 属性インデックス の新設

言語ごとの拡張・改善

OpenMP

  • CUDA API によるメモリアロケータ強化、Nvidia GPUでの性能向上
  • ompx_gnu_managed_mem_alloc など新アロケータ追加、ホスト側でデバイスアクセス可能なメモリ確保
  • OpenMP 5.0/5.1/5.2/6.0/TR14 の機能追加やAPI拡張
  • 非推奨構文 利用時の警告表示(-Wno-deprecated-openmpで抑制可能)

OpenACC

  • acc_memcpy_deviceacc_memcpy_device_async APIの追加
  • OpenACC 3.0/3.3/3.4 対応の拡張、Fortranでの定数利用も許可

Ada

  • Constructor/Destructor拡張 による新しい構築・終了メカニズム
  • Implicit withStructural Generic instantiation などの新機能
  • Extended_Access で他言語連携や配列スライス対応
  • VAST によるセマンティックツリーチェック機能
  • Ada 2022 の機能強化やAndroidサポート向上

C++

  • C++20 がデフォルト標準(-std=gnu++20)、古い標準利用時は明示指定が必要
  • C++26/C++23 の一部機能実装(Reflection, Contracts, Structured bindings等)
  • エラーメッセージ の階層・インデント表示、従来形式への切り替えも可能
  • C++20モジュール の実験的サポート強化(--compile-std-moduleなど)
  • 標準ライブラリ(libstdc++) でのABI変更や新機能追加
    • std::variant ABI のC++20準拠化
    • std::regex がヒープベーススタック利用で大規模文字列対応
    • C++20/23/26 の新コンポーネント対応(std::simd, std::inplace_vector等)

Fortran

  • Coarray による共有メモリマルチスレッド対応
  • Fortran 2003 のパラメータ化派生型サポート強化

非互換・注意点

  • Solaris での型やオプションの変更による移植性への注意
  • C++20 のサポートはGCC 16以前と互換性がない場合あり
  • std::variant など一部ABI変更により、既存コードの動作・バイナリ互換性への影響

参考情報

  • Porting to GCC 16 ページや GCC公式ドキュメント で詳細確認推奨
  • 各言語・機能ごとの詳細は 該当Wikiやリリースノート 参照

Hackerたちの意見

なんか、GCCのリリーススケジュールがすごく規則的だってことに、今調べるまで気づかなかったわ。https://gcc.gnu.org/develop.html

確か、GCCがGPL3に移行してからだよね。それまでは遅かったし、GCC 2.95のC++バグに対処するのに時間をかけすぎたな(問題のあったバージョンを覚えてるってことは、そういうことだよね :)

そうそう、最近のGCCのメジャーリリースは、Fedoraの春のリリースみたいにすごく規則的だよね。リリースのリズムも同じような感じだし。ヒント?Red Hat。

それは、Cygnus(今はRedHat→IBM)の人たちがプロジェクトを再編成してからずっとそうだよ。

大きなプロジェクトは、ずっと定期的なリリーススケジュールに移行してきたよね。90年代までは、みんなが望む機能を全部詰め込んだ大きなリリースを一気に出せると思ってたけど(小さなプロジェクトにはまだいいアイデアだけど)、プロジェクトが大きくなると(場合によっては小さくても)、誰かがまだ準備できてない機能に取り組んでることが多くなるから、定期的なリリースがあると、顧客をサポートし続けられるんだよね。これによって、準備ができてるか不安な開発者は「この不安定な機能を無効にする」トグルを持つことを強いられる。それが今できる最善の策だよ。

もうしばらく使ってるよ(debian sidにはトランクパッケージがある)。C++26のリフレクションがあって、リフレクションを使っていろいろ魔法みたいなことしてる(特にシリアライズ・デシリアライズにはすごく便利)。エコシステムにLSPサーバーがあればいいのに!

libstdが原因で、Debian 12と13でgcc 16のバイナリがうまく動かない問題が出てる。

みんなが採用すべきだと思う実装された機能を指摘したいけど、あまり広まらないだろうなと思う:P2590R2、明示的なライフタイム管理(PR106658)。これは「std::start_lifetime_as」のためのもの。聞いたことがないなら、構造体型にポインタを型変換する非未定義動作(non-UB)な方法だよ。外部I/Oバッファを扱うほとんどのゼロコピーコードは、こんな感じになる:std::unique_ptr buffer = stream->read(); if (buffer[0] == FOO) processFoo(reinterpret_cast(buffer.get())); // 未定義動作 else processBar(reinterpret_cast(buffer.get())); // 未定義動作。これがマージされれば、reinterpret_castをstart_lifetime_asに置き換えるだけで、もう悪いことはしないよ。https://en.cppreference.com/cpp/memory/start_lifetime_as

パンのキャラクターバッファをタイプするのは許可されてるよ。

あなたのコードは naughty どころか、アライメントの問題で間違ってるよ。

これを達成するための合法的な方法はすでにあって、みんなそれを使ってるはずだよ(ノーオペのmemmoveを通してポインタを洗浄する)。ここでreinterpret_castを使うのはバグだね。「start_lifetime_as」機能は、メモリ洗浄の呪文にきれいな標準名を提供する以上のことを一つ追加でやってる。意味的にはメモリに触れないけど、ノーオペのmemmoveは本質的に触れる。実際には、コンパイラがmemmoveがノーオペだと見抜いて最適化するから、あまり違いはないけどね。

cppreferenceの説明はちょっと疑わしいと思うな。> T型の完全なオブジェクト(アドレスがp)とその中にネストされたオブジェクトを暗黙的に作成する。TriviallyCopyable型Uの各作成されたオブジェクトobjの値は、std::bit_cast(E)を呼び出すのと同じ方法で決定されるが、実際にはストレージにはアクセスされない。Eはobjを示すU型の左辺値。そうでなければ、そうして作成されたオブジェクトの値は未指定。だからTは完全な新しいオブジェクト。サブオブジェクトを含んでいて、その中の一つがU型。Uはbit_castで初期化されて、彼らはbit_castが問題のアドレスに既に存在するビットからキャストされたと言いたかったんだと思う。「obj」がどんな定義もなしに言及されてるから、正しいアドレスにある何かを意味してると仮定する。でもEは何?ページには「Eはobjを示すU型の左辺値」と書いてあるけど、objはおそらくchar型か似たような型で、もし既にU型だったらbit_castの必要はないよね。

-Ofastって、-fno-fast-mathを無視するのまだ続いてるの?

不安定なソースをこの3ヶ月くらい試してみたけど、いくつかのプログラムで問題があったんだ(最近のGCCではコンパイルできなかったけど、古いGCCでは問題なかった)。だから、今のところgcc 15.xの方が全体的にうまくいってる。ただ、3000以上のプログラムの中で、大多数は問題なく動くし、いくつかはパッチが必要かも(ちなみに、LFS/BLFSで見つかることが多いよ。個々の問題を修正するためにsedの指示を使って、だいたいはうまくいく)。その問題が解決されてるといいな。みんな安定性と動作することが必要だから。

初心者の質問なんだけど、gccは内部でLLVMを使ってるの?それとも独自のコード生成と最適化パイプラインがあるの?LLVMと比べてどうなの?

gccは内部でLLVMを使ってるの? 使ってないよ。

gccは内部でLLVMを使ってるの?それとも独自のコード生成と最適化パイプラインを持ってるの? 使ってないよ。 LLVMと比べてどうなの? まあ、gccはLLVMよりも多くのターゲットをサポートしてるし、ほとんどの場合、似たような、もしくはそれ以上の実行ファイルを生成するよ。