[インデックス 13845] ファイルの概要
このコミットは、Goコンパイラおよび関連ツールチェーンのビルドプロセスにおいて、Plan 9オペレーティングシステム向けに発生していた「set and not used」(設定されたが使用されていない)という警告を修正するものです。具体的には、Goのコンパイラ(gc
)、リンカ(ld
)、およびランタイム(runtime
)のC言語ソースコード内で、宣言された変数や引数が実際には使用されていないために発生する警告を解消しています。これにより、ビルドプロセスのクリーンさを保ち、潜在的なバグの兆候を見逃さないようにすることが目的です。
コミット
- コミットハッシュ:
b29ed23ab55477dbdc02ee9fd4bf711e0b296f6a
- 作者: Lucio De Re lucio.dere@gmail.com
- コミット日時: 2012年9月17日(月)17:25:26 -0400
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b29ed23ab55477dbdc02ee9fd4bf711e0b296f6a
元コミット内容
build: fix various 'set and not used' for Plan 9
R=dave, minux.ma, rsc
CC=golang-dev
https://golang.org/cl/6501134
変更の背景
Go言語のコンパイラやツールチェーンは、複数のオペレーティングシステム(Linux, macOS, Windows, Plan 9など)をサポートするように設計されています。異なるOSやアーキテクチャ向けにビルドする際、特定のプラットフォームでのみ使用されない変数やコードパスが存在することがあります。
このコミットの背景には、主に以下の理由が考えられます。
- コンパイラ警告の抑制: C言語のコンパイラ(特にGoのツールチェーンで使用される
gc
コンパイラなど)は、変数が宣言され、値が代入されたにもかかわらず、その後に一度も使用されない場合に「set and not used」という警告を発することが一般的です。これらの警告は、コードの潜在的なバグ(例えば、変数の誤用やロジックの欠陥)を示唆する可能性があるため、通常は修正が推奨されます。 - ビルドのクリーンさ: 警告が多数存在すると、本当に重要な警告やエラーメッセージが埋もれてしまい、開発者が問題を見落とすリスクが高まります。ビルドプロセスを警告なしに保つことは、コードベースの健全性を維持し、開発効率を向上させる上で重要です。
- Plan 9固有の問題: コミットメッセージに「for Plan 9」と明記されていることから、これらの警告が特にPlan 9環境でのビルド時に顕著であったか、あるいはPlan 9固有のコードパスで発生していたことが示唆されます。これは、クロスプラットフォーム開発における一般的な課題の一つです。
前提知識の解説
「set and not used」警告
C言語やC++などのコンパイラが発する警告の一種で、変数が宣言され、初期化または値が代入されたにもかかわらず、その変数の値が後続のコードで一度も読み取られたり、利用されたりしない場合に発生します。
例:
int x = 10; // x は設定された
// ... x はどこでも使われない ...
この場合、コンパイラはx
が「set and not used」であると警告します。
警告の意義:
- 潜在的なバグ: 変数に値が代入されたが使われていない場合、それはプログラマの意図と異なるロジックになっている可能性があります。例えば、計算結果を格納するつもりが、その結果を後で利用し忘れている、といったケースです。
- デッドコード: 使用されない変数は、コンパイル時に最適化によって削除されることがありますが、ソースコード上は無駄な記述であり、コードの可読性を低下させます。
- コードの健全性: 警告を放置すると、本当に重要な警告やエラーメッセージが埋もれてしまい、開発者が問題を見落とす原因となります。
Plan 9
Plan 9 from Bell Labsは、ベル研究所で開発された分散オペレーティングシステムです。Unixの後継として設計され、ネットワーク透過性、ファイルシステム中心の設計、UTF-8の採用など、多くの革新的な概念を導入しました。Go言語の開発者の一部(Rob Pike, Ken Thompsonなど)はPlan 9の開発にも深く関わっており、Go言語の設計思想にもPlan 9の影響が見られます。GoのツールチェーンがPlan 9をサポートしているのは、このような歴史的背景があるためです。
USED
マクロ/関数
C言語のコードベースでは、コンパイラが「set and not used」警告を発するのを意図的に抑制するために、USED
という名前のマクロや関数が慣習的に使用されることがあります。これは、変数が実際には使用されないが、特定の状況下でその変数を宣言・設定する必要がある場合に役立ちます。
一般的な実装例:
#define USED(x) (void)(x)
または
static void USED(void *x) { (void)x; }
このマクロは、引数として渡された変数をvoid
型にキャストするだけの操作を行います。これにより、コンパイラはその変数が「使用された」と認識し、警告を抑制します。実際には何も処理を行わないため、実行時のオーバーヘッドはほとんどありません(最適化によって完全に削除されることがほとんどです)。
このコミットでは、まさにこのUSED
マクロが活用されています。
技術的詳細
このコミットの技術的詳細は、主にGoコンパイラ(gc
)、リンカ(ld
)、およびランタイム(runtime
)のC言語ソースコードにおける「set and not used」警告の具体的な修正方法に集約されます。
修正方法は大きく分けて2種類あります。
- 未使用変数の削除: 変数が完全に不要であり、その値がどこでも使われていない場合、その変数の宣言や代入自体を削除します。
USED
マクロの適用: 変数が特定の状況下で必要だが、直接的なコードロジックでは使用されない(例えば、デバッグ目的、将来の拡張のためのプレースホルダー、あるいは特定のプラットフォームでのみ未使用となる場合)場合に、USED(variable_name);
という形式でマクロを適用し、コンパイラにその変数が「使用されている」と認識させ、警告を抑制します。
このコミットでは、後者のUSED
マクロの適用が主な修正方法として採用されています。これは、変数が完全に不要なわけではなく、特定のビルドターゲット(この場合はPlan 9)でのみ未使用となる状況に対応するためと考えられます。
具体的な変更点を見ると、src/cmd/8g/reg.c
では未使用の変数代入が削除されていますが、他のファイルでは主にUSED()
マクロが追加されています。
コアとなるコードの変更箇所
このコミットでは、以下の7つのファイルが変更されています。
src/cmd/8g/reg.c
:r1 = R;
の行が削除されました。r1
という変数が設定された後、使用されていなかったため、その代入自体が不要と判断されました。
src/cmd/gc/closure.c
:walkcallclosure
関数内で、USED(init);
が追加されました。init
引数が特定のコードパスで直接使用されていなかったため、警告を抑制するために明示的に「使用済み」とマークされました。
src/cmd/gc/esc.c
:esctag
関数内で、USED(e);
が追加されました。e
引数が特定のコードパスで直接使用されていなかったため、警告を抑制するために明示的に「使用済み」とマークされました。
src/cmd/gc/mparith1.c
:mpatoflt
関数内で、switch(c = *s++)
がswitch(*s++)
に変更されました。c
という変数がswitch
文の条件式内で設定された後、その値がswitch
ブロック内で使用されていなかったため、c
への代入自体が不要と判断され削除されました。
src/cmd/gc/reflect.c
:typestruct
関数内で、USED(t);
が追加されました。t
引数が特定のコードパスで直接使用されていなかったため、警告を抑制するために明示的に「使用済み」とマークされました。
src/cmd/ld/go.c
:loaddynlinker
関数内で、USED(pkg);
が追加されました。pkg
引数が特定のコードパスで直接使用されていなかったため、警告を抑制するために明示的に「使用済み」とマークされました。
src/pkg/runtime/thread_plan9.c
:runtime·badsignal
関数内で、USED(sig);
が追加されました。sig
引数が特定のコードパスで直接使用されていなかったため、警告を抑制するために明示的に「使用済み」とマークされました。
コアとなるコードの解説
このコミットの主要な変更は、Goのコンパイラ、リンカ、およびランタイムのC言語ソースコードにおける未使用変数警告の修正です。
src/cmd/8g/reg.c
の変更
--- a/src/cmd/8g/reg.c
+++ b/src/cmd/8g/reg.c
@@ -147,7 +147,6 @@ regopt(Prog *firstp)
return;
}
- r1 = R;
firstr = R;
lastr = R;
ここでは、r1 = R;
という行が削除されています。これは、r1
という変数がこの行でR
の値に設定された後、その後のコードで一度も使用されていなかったため、完全に不要な代入であったと判断されたためです。このような修正は、コードの冗長性を減らし、コンパイラ警告を直接的に解消します。
src/cmd/gc/closure.c
, src/cmd/gc/esc.c
, src/cmd/gc/reflect.c
, src/cmd/ld/go.c
, src/pkg/runtime/thread_plan9.c
の変更
これらのファイルでは、同様のパターンでUSED()
マクロが追加されています。
例: src/cmd/gc/closure.c
--- a/src/cmd/gc/closure.c
+++ b/src/cmd/gc/closure.c
@@ -252,6 +252,7 @@ walkclosure(Node *func, NodeList **init)
void
walkcallclosure(Node *n, NodeList **init)
{
+ USED(init);
if (n->op != OCALLFUNC || n->left->op != OCLOSURE) {
dump("walkcallclosure", n);
fatal("abuse of walkcallclosure");
walkcallclosure
関数のinit
引数は、特定のコードパスでは使用されないにもかかわらず、関数シグネチャの一部として存在しています。このような場合、引数を削除することはできませんが、コンパイラ警告を抑制するためにUSED(init);
が追加されます。これにより、コンパイラはinit
が「使用された」とみなし、警告を発しなくなります。これは、特にクロスプラットフォーム開発において、特定のOSやアーキテクチャでのみ使用されない変数や引数がある場合に有効な手法です。
src/cmd/gc/mparith1.c
の変更
--- a/src/cmd/gc/mparith1.c
+++ b/src/cmd/gc/mparith1.c
@@ -288,7 +288,7 @@ mpatoflt(Mpflt *a, char *as)
s = as;
base = -1;
while(base == -1) {
- switch(c = *s++) {
+ switch(*s++) {
case '-':
case '+':
break;
ここでは、switch(c = *s++)
がswitch(*s++)
に変更されています。元のコードでは、*s++
の結果が変数c
に代入されていましたが、その後のswitch
ブロック内で変数c
が使用されていませんでした。この変更により、不要な変数c
への代入が削除され、警告が解消されます。これは、src/cmd/8g/reg.c
の変更と同様に、完全に不要な代入を削除するケースです。
これらの変更は、GoのツールチェーンのC言語部分におけるコード品質とビルドのクリーンさを向上させるための、細かではあるが重要な修正です。
関連リンク
- Go Gerrit Code Review: https://golang.org/cl/6501134
参考にした情報源リンク
- Go言語のソースコード(本コミットのdiff)
- C言語における「unused variable」警告と
USED
マクロに関する一般的な知識 - Plan 9オペレーティングシステムに関する一般的な知識