Go 1.27からgoコマンドは、go.modやソースの//go:debugコメントで指定された削除済みGODEBUG設定が削除前の最終デフォルト値であればビルドエラーにしなくなった。
GODEBUG
概要
Go 1.27から、go コマンドは go.mod の godebug エントリや .go ソースファイルの //go:debug コメントに、サポートが削除された GODEBUG 設定(asynctimerchan など)が書かれていても、それが削除される前に確立された最終的なデフォルト値に設定されている場合はビルドエラーにしないようになった。設定が古い値(削除前の非デフォルト値)になっている場合は、従来どおり go コマンドがエラーで失敗する。この変更はGo 1 compatibility guaranteeの精神に沿ったもので、対応するGODEBUG設定のサポートが将来削除された後も、その設定を最終デフォルト値で使っている既存プログラムを変更なしにビルド・実行し続けられるようにする。
導入経緯
Issue #79422は、Proposal #76163が採択されればGODEBUG設定を削除後もそのデフォルト値であれば使い続けられるはずだが、当時は削除済みGODEBUGの値が最終デフォルト値であっても //go:debug gotypesalias=1 のようなコメントがビルドエラーになってしまうという問題として報告された。この issue はProposal #76163の採択を前提にGo 1.27のリリースブロッカーとして扱われ、CL 784221(cmd/go: allow default settings for removed godebugs)で修正が実装された。あわせてCL 786260でリリースノートの記載が追加されている。
議論のハイライト
- Proposal #76163の採択を前提として、Go 1.27のリリースブロッカーとしてマークされた。
- 修正自体はCL 784221
cmd/go: allow default settings for removed godebugsとして実装された。 - リリースノートへの反映はCL 786260
_content/doc: document new cmd/go GODEBUG behavior (update release notes)で行われた。
使用例
Before
//go:debug gotypesalias=1
package main
func main() {}
Go 1.26以前では、gotypesalias のように既にサポートが削除されたGODEBUG設定が書かれている場合、たとえ値が削除前の最終デフォルト値(gotypesalias なら "1")であってもビルドエラーになっていた。
After
//go:debug gotypesalias=1
package main
func main() {}
Go 1.27では同じソースがそのままビルドできる。gotypesalias の削除前の最終デフォルト値が "1" であるため、go コマンドはこの設定を許容する。
移行時の注意
go.mod の godebug エントリや //go:debug コメントに、削除済みGODEBUG設定を削除前の古い(非デフォルトの)値のまま残している場合は、Go 1.27へのアップグレード後もビルドエラーになる点は変わらない。その場合は設定を削除前の最終デフォルト値に書き換えるか、設定自体を削除する必要がある。
実装解説
go コマンドは //go:debug コメントと go.mod の godebug エントリの両方を、modload.CheckGodebugという共通関数でチェックしている。この関数は対象のキーがinternal/godebugs.Removedテーブルに含まれる場合、そのエントリが持つ Old 述語関数で値が「削除前の古い値」かどうかを判定し、古い値のときだけエラーを返す(それ以外の値、つまり最終デフォルト値は許容する)。Removed テーブルの各エントリは Name(設定名)・Removed(削除されたGoのマイナーバージョン)・Old(古い値かどうかを判定する関数)を持ち、asynctimerchan のように複数の値を「古い」とみなす設定にも対応できるよう Old は単純な文字列比較ではなく述語関数になっている。//go:debug コメント側はload.ParseGoDebugがコメントをパースしたうえで同じ CheckGodebug を呼び出しており、go.mod の godebug エントリと同一のルールが適用される。