[インデックス 14936] ファイルの概要
このコミットは、Goコンパイラの複数のコンポーネント(cmd/8g
, cmd/dist
, cmd/gc
)におけるPlan 9環境でのコンパイル時の警告を修正するものです。具体的には、以下の5つのファイルが変更されています。
src/cmd/8g/gsubr.c
src/cmd/8g/reg.c
src/cmd/dist/plan9.c
src/cmd/gc/fmt.c
src/cmd/gc/racewalk.c
コミット
- コミットハッシュ:
2bddbf5e8f864890f5a8cda1a5e00dbf04b4f7e9
- 作者: Anthony Martin ality@pbrane.org
- コミット日時: 2013年1月18日 金曜日 19:08:00 -0800
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/2bddbf5e8f864890f5a8cda1a5e00dbf04b4f7e9
元コミット内容
cmd/8g, cmd/dist, cmd/gc: fix warnings on Plan 9
cmd/8g/gsubr.c: unreachable code
cmd/8g/reg.c: overspecifed class
cmd/dist/plan9.c: unused parameter
cmd/gc/fmt.c: stkdelta is now a vlong
cmd/gc/racewalk.c: used but not set
R=golang-dev, seed, rsc
CC=golang-dev
https://golang.org/cl/7067052
変更の背景
このコミットの主な目的は、GoコンパイラをPlan 9オペレーティングシステム上でコンパイルする際に発生していた複数の警告を解消することです。警告はコンパイルプロセスを妨げるものではありませんが、コードの品質低下、潜在的なバグの兆候、または将来のコンパイラバージョンでのエラー発生リスクを示唆する可能性があります。特に、クロスコンパイル環境や特定のアーキテクチャ(この場合はPlan 9)に特有の警告は、その環境でのGoの安定性と互換性を確保するために重要です。
具体的には、以下の問題が指摘されていました。
cmd/8g/gsubr.c
: 到達不能なコード(unreachable code)が存在し、コンパイラが警告を発していました。これは通常、コードの論理フローに問題があるか、デッドコードが存在することを示します。cmd/8g/reg.c
: クラスの指定が過剰(overspecified class)であるという警告が出ていました。これは、変数のスコープやリンケージ指定が不適切である可能性を示唆します。cmd/dist/plan9.c
: 未使用のパラメータ(unused parameter)が存在し、警告の原因となっていました。これは、関数シグネチャに定義されているが、関数本体で一度も使用されていない引数がある場合に発生します。cmd/gc/fmt.c
:stkdelta
変数の型が、Plan 9のCコンパイラ環境においてvlong
(64ビット整数)として扱われるべきであるにもかかわらず、異なる型で扱われていたため、フォーマット文字列の不一致による警告が発生していました。cmd/gc/racewalk.c
: 変数が使用されているにもかかわらず、初期化されていない(used but not set)という警告が出ていました。これは未定義動作を引き起こす可能性があり、非常に危険な警告です。
これらの警告を修正することで、Plan 9環境でのGoコンパイラのビルドプロセスがクリーンになり、より堅牢なコードベースが維持されます。
前提知識の解説
Plan 9 from Bell Labs
Plan 9 from Bell Labsは、ベル研究所で開発された分散オペレーティングシステムです。Unixの後継として設計され、"Everything is a file"(すべてはファイルである)という哲学を徹底しています。ネットワーク透過性、UTF-8の採用、新しいプロトコル(9P)などが特徴です。Go言語の開発者の一部(Rob Pike, Ken Thompsonなど)はPlan 9の開発にも深く関わっており、Go言語の設計思想にはPlan 9の影響が色濃く反映されています。GoコンパイラがPlan 9をターゲットとしてサポートしていたのは、このような歴史的背景と、Plan 9が提供するクリーンな環境が開発に適していたためです。
Goコンパイラの主要コンポーネント(2013年頃の状況)
Go言語のコンパイラは、その開発初期から独自のツールチェインを持っていました。2013年頃のGoコンパイラは、主にC言語で書かれており、以下のようなコンポーネントで構成されていました。
cmd/8g
(または6g
,5g
など): 特定のアーキテクチャ(例:8g
はx86、6g
はamd64、5g
はARM)向けのGoコンパイラのフロントエンドおよびバックエンドの一部を担っていました。Goソースコードをアセンブリコードに変換する役割を持っていました。cmd/gc
: Goコンパイラの主要な部分であり、型チェック、AST(抽象構文木)の構築、最適化、コード生成など、コンパイルプロセスの中心的な役割を担っていました。8g
などのアーキテクチャ固有のコンパイラと連携して動作しました。cmd/dist
: Goのツールチェインのビルドと配布を管理するコマンドです。コンパイラ、リンカ、アセンブラなどのツールをビルドし、Goのインストール環境を構築するために使用されました。
これらのコンポーネントは、Go言語のソースコードを最終的な実行可能バイナリに変換する一連のプロセスを形成していました。
C言語のコンパイラ警告
C言語のコンパイラは、プログラムの潜在的な問題や非効率性を示すために警告を発します。これらはエラーとは異なり、プログラムのコンパイルを停止させることはありませんが、無視すべきではありません。
unreachable code
(到達不能なコード): コードの特定のセクションが、プログラムの実行フローにおいて決して到達しないことを示します。これは通常、return
文、break
文、continue
文、または無限ループの後に続くコードブロックで発生します。デッドコードであり、削除するか、論理を見直す必要があります。overspecified class
(クラスの指定が過剰): 変数や関数のリンケージ(外部リンケージ、内部リンケージなど)やストレージクラス(static
,extern
,auto
,register
など)の指定が、そのコンテキストにおいて冗長または不適切であることを示します。例えば、ファイルスコープのstatic
変数を関数内で再度static
と宣言するなどです。unused parameter
(未使用のパラメータ): 関数の引数として宣言されている変数が、関数本体のどこでも使用されていないことを示します。これは、プログラマの意図しない引数、または将来の機能のために予約された引数である可能性があります。警告を抑制するために、Plan 9のCコンパイラではUSED()
マクロがよく用いられます。used but not set
(使用されているが設定されていない): 変数が使用される前に値が割り当てられていないことを示します。これは未定義動作(Undefined Behavior)を引き起こす可能性があり、プログラムのクラッシュや予期せぬ結果につながる非常に危険な警告です。vlong
: Plan 9のCコンパイラ(8c
,6c
など)における64ビット整数型です。一般的なC言語のlong long
に相当します。printf
系の関数でvlong
を正しく出力するためには、対応するフォーマット指定子(例:%lld
)を使用する必要があります。
技術的詳細
このコミットは、GoコンパイラのC言語ソースコードにおける特定の警告を、最小限の変更で修正しています。
-
cmd/8g/gsubr.c: unreachable code
の修正:floatmove
関数内で、gins(a, f, t); return;
という行が、その直前のif
ブロックの条件が満たされた場合にのみ実行されるべきロジックの後に、無条件に配置されていました。しかし、その後のhard:
ラベルへのジャンプが存在するため、gins
とreturn
の行は常にスキップされ、到達不能となっていました。このコミットでは、この到達不能な2行を削除することで警告を解消しています。これはデッドコードの削除であり、プログラムの動作には影響しません。 -
cmd/8g/reg.c: overspecified class
の修正:fixtemp
関数は、ファイルスコープで定義されており、その前にvoid
がついていました。Plan 9のCコンパイラでは、ファイルスコープの関数はデフォルトで外部リンケージを持つため、static
キーワードを明示的に追加することで、その関数が現在の翻訳単位(ファイル)内でのみ使用されることを示し、リンケージの指定を明確にしています。これにより、「overspecified class」の警告が解消されます。static
キーワードの追加は、関数の可視性をファイル内に限定し、他のファイルからのアクセスを防ぎます。 -
cmd/dist/plan9.c: unused parameter
の修正:xtryexecfunc
関数は、void (*f)(void)
という関数ポインタを引数として受け取りますが、関数本体ではこのf
パラメータが使用されていませんでした。Plan 9のCコンパイラでは、未使用のパラメータに対して警告を発します。この修正では、USED(f);
というマクロを追加しています。USED()
マクロは、Plan 9のCコンパイラが提供する慣用的な方法で、特定の変数が意図的に未使用であることをコンパイラに伝えるために使用されます。これにより、警告が抑制されます。 -
cmd/gc/fmt.c: stkdelta is now a vlong
の修正:Jconv
関数内で、fmtprint
関数(Plan 9のprintf
に相当する関数)を使用してn->stkdelta
の値をフォーマット出力していました。元のコードでは%lld
というフォーマット指定子を使用していましたが、これはlong long
型に対応するものです。しかし、Plan 9のCコンパイラ環境では、stkdelta
がvlong
型として扱われるべきであり、vlong
はlong long
とは異なる内部表現を持つか、あるいはコンパイラが異なるフォーマット指定子を期待している可能性がありました。この修正では、n->stkdelta
のフォーマット指定子を%lld
から%lld
に変更しています。これは一見同じに見えますが、元のコードのコメントアウトされた部分や、コンパイラの特定のバージョンにおけるvlong
の扱いに関する微妙な違いに対応している可能性があります。特に、fmtprint(fp, " x(%lld%+d)", n->xoffset, n->stkdelta);
からfmtprint(fp, " x(%lld%+lld)", n->xoffset, n->stkdelta);
への変更は、stkdelta
がint
ではなくlong long
(またはvlong
)として扱われるべきであることを明確に示しています。これにより、型とフォーマット指定子の不一致による警告が解消されます。 -
cmd/gc/racewalk.c: used but not set
の修正:racewalknode
関数内で、n1
という変数がUSED(n1);
によって未使用であるとマークされているにもかかわらず、その直前のコメントアウトされたコードブロック内でn1 = nod(OADDR, n->left, N);
のように値が設定される可能性がありました。しかし、このコメントアウトされたコードが有効でない場合、n1
は使用される(USED(n1)
)が、値が設定されない状態になり、警告が発生します。この修正では、SET(n1);
というマクロを追加しています。SET()
マクロは、Plan 9のCコンパイラが提供する別の慣用的なマクロで、変数が意図的に設定されている(または、コンパイラがその変数が設定されていると見なすべきである)ことを示すために使用されます。これにより、「used but not set」の警告が抑制されます。
コアとなるコードの変更箇所
diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c
index b101d14a83..4c86b7582e 100644
--- a/src/cmd/8g/gsubr.c
+++ b/src/cmd/8g/gsubr.c
@@ -1515,7 +1515,7 @@ floatmove(Node *f, Node *t)
{
Node r1, r2, t1, t2, tlo, thi, con, f0, f1, ax, dx, cx;
Type *cvt;
- int a, ft, tt;
+ int ft, tt;
Prog *p1, *p2, *p3;
ft = simsimtype(f->type);
@@ -1711,9 +1711,6 @@ floatmove(Node *f, Node *t)
return;
}\n
-\tgins(a, f, t);\n
-\treturn;\n
-\n
hard:
// requires register intermediate
regalloc(&r1, cvt, t);
diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c
index 7b8b39e8bc..4e516b82a6 100644
--- a/src/cmd/8g/reg.c
+++ b/src/cmd/8g/reg.c
@@ -1815,7 +1815,7 @@ hash32to16(uint32 h)
* sees, which lets it do a better job and makes it less likely to turn
* itself off.
*/
-void
+static void
fixtemp(Prog *firstp)
{
static uint8 counts[1<<16]; // A hash table to count variable occurences.
diff --git a/src/cmd/dist/plan9.c b/src/cmd/dist/plan9.c
index 56f922ced6..f289f5213c 100644
--- a/src/cmd/dist/plan9.c
+++ b/src/cmd/dist/plan9.c
@@ -755,6 +755,7 @@ xsamefile(char *f1, char *f2)
int
xtryexecfunc(void (*f)(void))
{\n
+\tUSED(f);\n
return 0; // suffice for now
}\n
diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c
index cbaba467e8..3ff212ea33 100644
--- a/src/cmd/gc/fmt.c
+++ b/src/cmd/gc/fmt.c
@@ -289,7 +289,7 @@ Jconv(Fmt *fp)
fmtprint(fp, " l(%d)", n->lineno);
if(!c && n->xoffset != BADWIDTH)
- fmtprint(fp, " x(%lld%+d)", n->xoffset, n->stkdelta);
+ fmtprint(fp, " x(%lld%+lld)", n->xoffset, n->stkdelta);
if(n->class != 0) {
s = "";
diff --git a/src/cmd/gc/racewalk.c b/src/cmd/gc/racewalk.c
index d744cea91e..5fa74ff20e 100644
--- a/src/cmd/gc/racewalk.c
+++ b/src/cmd/gc/racewalk.c
@@ -219,6 +219,7 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
racewalknode(&n->left, init, 0, 0);
if(istype(n->left->type, TMAP)) {
// crashes on len(m[0]) or len(f())
+\t\t\tSET(n1);\n
USED(n1);\n
/*\n
tn1 = nod(OADDR, n->left, N);\n
コアとなるコードの解説
src/cmd/8g/gsubr.c
- 変更前:
int a, ft, tt; // ... gins(a, f, t); return; // ... hard:
- 変更後:
int ft, tt; // 'a' が削除 // ... // gins(a, f, t); と return; の行が削除 // ... hard:
floatmove
関数内で、変数a
が宣言されていましたが、その後のコードで全く使用されていませんでした。また、gins(a, f, t); return;
の2行は、その直前のif
ブロックの条件が満たされない限り、常にhard:
ラベルへのジャンプによってスキップされるため、到達不能なコードとなっていました。この修正では、未使用の変数a
の宣言を削除し、到達不能なgins
とreturn
の行を削除することで、コンパイラの警告を解消し、コードをクリーンにしています。
src/cmd/8g/reg.c
- 変更前:
void fixtemp(Prog *firstp)
- 変更後:
static void fixtemp(Prog *firstp)
fixtemp
関数は、このファイル内でのみ使用されるべき内部関数です。C言語では、ファイルスコープで定義された関数はデフォルトで外部リンケージを持ちます。static
キーワードを追加することで、この関数のリンケージを内部リンケージに明示的に変更し、他のファイルからこの関数が参照されることを防ぎます。これにより、Plan 9のCコンパイラが発していた「overspecified class」の警告が解消されます。
src/cmd/dist/plan9.c
- 変更前:
int xtryexecfunc(void (*f)(void)) { return 0; // suffice for now }
- 変更後:
int xtryexecfunc(void (*f)(void)) { USED(f); // 追加 return 0; // suffice for now }
xtryexecfunc
関数は、引数f
(関数ポインタ)を受け取りますが、関数本体ではこのf
が使用されていませんでした。Plan 9のCコンパイラは、このような未使用のパラメータに対して警告を発します。USED(f);
マクロは、Plan 9のCコンパイラが提供する特殊なマクロで、特定の変数が意図的に未使用であることをコンパイラに伝えるために使用されます。これにより、警告が抑制されます。
src/cmd/gc/fmt.c
- 変更前:
fmtprint(fp, " x(%lld%+d)", n->xoffset, n->stkdelta);
- 変更後:
fmtprint(fp, " x(%lld%+lld)", n->xoffset, n->stkdelta);
Jconv
関数内で、n->stkdelta
の値をフォーマット出力する際に、元のコードでは%d
というフォーマット指定子を使用していました。しかし、n->stkdelta
はPlan 9のCコンパイラ環境においてvlong
(64ビット整数)として扱われるべき型でした。%d
は通常32ビット整数に対応するため、型とフォーマット指定子の不一致が発生し、警告の原因となっていました。この修正では、n->stkdelta
に対応するフォーマット指定子を%lld
に変更しています。%lld
はlong long
型(64ビット整数)に対応する標準的な指定子であり、これによりvlong
型のn->stkdelta
が正しくフォーマットされ、警告が解消されます。
src/cmd/gc/racewalk.c
- 変更前:
// ... if(istype(n->left->type, TMAP)) { // crashes on len(m[0]) or len(f()) // n1 = nod(OADDR, n->left, N); // コメントアウトされている USED(n1); /* tn1 = nod(OADDR, n->left, N); */ } // ...
- 変更後:
// ... if(istype(n->left->type, TMAP)) { // crashes on len(m[0]) or len(f()) SET(n1); // 追加 USED(n1); /* tn1 = nod(OADDR, n->left, N); */ } // ...
racewalknode
関数内で、変数n1
がUSED(n1);
によって「使用されている」とマークされているにもかかわらず、その直前のコード(コメントアウトされた行を含む)でn1
に値が割り当てられていない可能性がありました。これにより、コンパイラは「used but not set」(使用されているが設定されていない)という警告を発していました。SET(n1);
マクロは、Plan 9のCコンパイラが提供する別の慣用的なマクロで、変数が意図的に設定されている(または、コンパイラがその変数が設定されていると見なすべきである)ことをコンパイラに伝えるために使用されます。これにより、警告が抑制され、コードの健全性が保たれます。
関連リンク
- Go Gerrit Change-ID: https://golang.org/cl/7067052
参考にした情報源リンク
- Plan 9 from Bell Labs: https://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs
- Go言語の歴史とPlan 9の影響に関する情報源(一般的な知識に基づくため特定のURLはなし)
- C言語のコンパイラ警告に関する一般的な情報源(Stack Overflow, C言語の標準ドキュメントなど)
- Plan 9 Cコンパイラの
USED()
およびSET()
マクロに関する情報源(Plan 9のドキュメントやソースコード) - Goコンパイラの初期の構造に関する情報源(Goの公式ブログやドキュメント、Goのソースコードリポジトリ)