[インデックス 18062] ファイルの概要
このコミットは、Goコンパイラ(cmd/6g
、cmd/gc
)とリンカ(cmd/ld
)におけるPlan 9 AMD64アーキテクチャ関連のコンパイル警告を修正するものです。具体的には、フォーマット文字列の不一致や、変数が設定されたものの使用されていないという警告に対処しています。これらの警告は、コードの正確性や実行には直接影響しないものの、コンパイル時のノイズとなり、潜在的なバグを見逃す原因となる可能性があります。
コミット
commit 9607255760975d4392c1f72b5377c6293ef53c80
Author: David du Colombier <0intro@gmail.com>
Date: Wed Dec 18 20:20:46 2013 +0100
cmd/6g, cmd/gc, cmd/ld: fix Plan 9 amd64 warnings
warning: src/cmd/6g/reg.c:671 format mismatch d VLONG, arg 4
warning: src/cmd/gc/pgen.c:230 set and not used: oldstksize
warning: src/cmd/gc/plive.c:877 format mismatch lx UVLONG, arg 2
warning: src/cmd/gc/walk.c:2878 set and not used: cbv
warning: src/cmd/gc/walk.c:2885 set and not used: hbv
warning: src/cmd/ld/data.c:198 format mismatch s IND FUNC(IND CHAR) INT, arg 2
warning: src/cmd/ld/data.c:230 format mismatch s IND FUNC(IND CHAR) INT, arg 2
warning: src/cmd/ld/dwarf.c:1517 set and not used: pc
warning: src/cmd/ld/elf.c:1507 format mismatch d VLONG, arg 2
warning: src/cmd/ld/ldmacho.c:509 set and not used: dsymtab
R=golang-dev, gobot, rsc
CC=golang-dev
https://golang.org/cl/36740045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/9607255760975d4392c1f72b5377c6293ef53c80
元コミット内容
このコミットの目的は、GoコンパイラとリンカのPlan 9 AMD64ビルドにおいて発生していた複数のコンパイル警告を解消することです。警告は主に以下の2種類に分類されます。
- フォーマット文字列の不一致 (format mismatch):
print
関数(Plan 9 Cの標準出力関数)のフォーマット指定子と、対応する引数の型が一致していないために発生する警告。例えば、long long
型の値を%d
(int型用)で出力しようとしたり、ポインタを%lx
(unsigned longの16進数用)で出力しようとしたりするケースです。 - 設定されたが使用されていない変数 (set and not used): 変数が初期化または値が代入されたにもかかわらず、その後のコードで一度も使用されていない場合に発生する警告。これはデバッグコードや条件付きコンパイルブロック内でよく見られます。
これらの警告は、コンパイラがコードの潜在的な問題を指摘するものであり、修正することでコードの品質と保守性を向上させることができます。
変更の背景
Go言語のツールチェインは、当初からPlan 9というオペレーティングシステムの設計思想に強く影響を受けています。Goのコンパイラやリンカといったツール群は、Plan 9のC言語(8c
, 6c
, 5c
など)やアセンブラ(8a
, 6a
, 5a
など)のツールチェインをベースに開発されました。そのため、Goのツールチェインのソースコードには、Plan 9 Cの慣習や特定の関数(例: print
)が使用されています。
このコミットが行われた2013年当時、Goはまだ発展途上にあり、様々なプラットフォームやアーキテクチャへの対応を進めていました。Plan 9 AMD64環境でのビルド時に発生するこれらの警告は、コンパイラの出力が煩雑になるだけでなく、将来的な互換性の問題や、より深刻なバグの兆候を見逃すリスクをはらんでいました。開発者は、これらの警告を修正することで、クリーンなコンパイル環境を維持し、ツールチェインの堅牢性を高めることを目指しました。
前提知識の解説
このコミットを理解するためには、以下の知識が役立ちます。
1. Goツールチェインの構成
cmd/6g
: Go言語のコンパイラの一つで、AMD64 (x86-64) アーキテクチャ向けのGoソースコードをコンパイルします。Go 1.5以降はcmd/compile
に統合されましたが、このコミット当時はまだ独立したツールでした。cmd/gc
: Goコンパイラの共通フロントエンド部分です。プラットフォームに依存しないGo言語の構文解析、型チェック、中間表現への変換などを行います。cmd/ld
: Go言語のリンカです。コンパイルされたオブジェクトファイルやライブラリを結合し、実行可能ファイルを生成します。
2. Plan 9 C言語の慣習
GoのツールチェインはPlan 9 Cで書かれており、一般的なGCCなどのCコンパイラとは異なる慣習や拡張が存在します。
print
関数: Plan 9 Cにおける標準出力関数で、printf
に似ていますが、一部のフォーマット指定子や動作が異なります。USED
マクロ: Plan 9 Cの慣習で、変数が「設定されたが使用されていない」という警告を抑制するために使用されるマクロです。通常、デバッグ目的で値を代入したが、本番コードでは使用されない変数に対して適用されます。
3. C言語のフォーマット指定子
printf
やprint
のような関数では、出力するデータの型に合わせて適切なフォーマット指定子を使用する必要があります。
%d
:int
型(符号付き整数)%lld
:long long
型(符号付き長整数)%lx
:unsigned long
型(符号なし長整数)の16進数表現%p
: ポインタのアドレス
これらの指定子が引数の型と一致しない場合、コンパイラは警告を発し、未定義の動作を引き起こす可能性があります。
4. Plan 9 AMD64
Plan 9オペレーティングシステムがサポートするAMD64(x86-64)アーキテクチャのことです。Goツールチェインは、この環境で正しく動作するように設計されています。
技術的詳細
このコミットは、主に以下の2種類の警告に対する修正を行っています。
1. フォーマット文字列の不一致の修正
-
src/cmd/6g/reg.c:671
:- 元のコード:
print("bit=%2d et=%2E w=%d+%lld %#N %D flag=%d\\n", i, et, o, w, node, a, v->addr);
- 修正後:
print("bit=%2d et=%2E w=%lld+%lld %#N %D flag=%d\\n", i, et, o, w, node, a, v->addr);
- 変更点:
o
(オフセット)の出力フォーマットを%d
から%lld
に変更しました。これは、o
がlong long
型(またはそれに相当する大きな整数型)であるにもかかわらず、int
型用の%d
が使われていたためです。VLONG
という警告メッセージから、long long
型が期待されていることがわかります。
- 元のコード:
-
src/cmd/gc/plive.c:877
:- 元のコード:
print("node=%lx, node->class=%d\\n", (uintptr)ll->n, ll->n->class);
- 修正後:
print("node=%p, node->class=%d\\n", (uintptr)ll->n, ll->n->class);
- 変更点: ポインタ
ll->n
をuintptr
にキャストして出力する際のフォーマットを%lx
から%p
に変更しました。%lx
はunsigned long
の16進数表現用ですが、ポインタのアドレスを出力するには%p
がより適切で、移植性も高いです。UVLONG
という警告メッセージは、unsigned long long
型が期待されていることを示唆しています。
- 元のコード:
-
src/cmd/ld/data.c:198
,src/cmd/ld/data.c:230
:- 元のコード:
diag("unhandled pcrel relocation for %s", headtype);
- 修正後:
diag("unhandled pcrel relocation for %s", headstring);
- 変更点:
diag
関数(エラー診断メッセージ出力関数)に渡す引数をheadtype
からheadstring
に変更しました。%s
フォーマット指定子は文字列を期待しますが、headtype
は文字列ではない型(おそらく整数や列挙型)であったため、headstring
という適切な文字列変数に置き換えることで警告を解消しました。
- 元のコード:
-
src/cmd/ld/elf.c:1507
:- 元のコード:
diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
- 修正後:
diag("ELFRESERVE too small: %lld > %d", a, ELFRESERVE);
- 変更点: 変数
a
の出力フォーマットを%d
から%lld
に変更しました。a
がlong long
型(VLONG
)であるにもかかわらず、int
型用の%d
が使われていたためです。
- 元のコード:
2. 「設定されたが使用されていない」変数の修正
-
src/cmd/gc/pgen.c:230
:- 元のコード:
if(0) print("allocauto: %lld to %lld\\n", oldstksize, (vlong)stksize);
- 修正後:
if(0) print("allocauto: %lld to %lld\\n", oldstksize, (vlong)stksize); USED(oldstksize);
- 変更点:
oldstksize
変数がif(0)
という常に偽となる条件ブロック内でしか使用されていなかったため、コンパイラが「設定されたが使用されていない」と判断していました。USED(oldstksize);
マクロを追加することで、この警告を明示的に抑制しました。これは、デバッグ目的で変数が存在し、将来的に使用される可能性があることをコンパイラに伝える一般的な方法です。
- 元のコード:
-
src/cmd/gc/walk.c:2878
,src/cmd/gc/walk.c:2885
:- 元のコード:
if(cbv < 0 || cbv > bv) { yyerror("slice index out of bounds"); cbv = -1; // この行が警告の原因 } // ... if(hbv < 0 || hbv > bv) { yyerror("slice index out of bounds"); hbv = -1; // この行が警告の原因 }
- 修正後:
if(cbv < 0 || cbv > bv) yyerror("slice index out of bounds"); // ... if(hbv < 0 || hbv > bv) yyerror("slice index out of bounds");
- 変更点:
cbv = -1;
とhbv = -1;
の行を削除しました。これらの変数は、yyerror
が呼び出された後にif
ブロック内で再利用されることがなかったため、「設定されたが使用されていない」という警告が発生していました。yyerror
は通常、コンパイルエラーを報告し、処理を中断するか、後続のコードが実行されないことを前提としているため、これらの代入は冗長であり、削除してもロジックに影響はありません。
- 元のコード:
-
src/cmd/ld/dwarf.c:1517
:- 元のコード:
pc = 0;
- 修正後: この行を削除。
- 変更点:
pc
変数が初期化された後、その後のコードで全く使用されていなかったため、初期化自体を削除しました。これにより、警告が解消されます。
- 元のコード:
-
src/cmd/ld/ldmacho.c:509
:- 元のコード:
dsymtab = nil;
- 修正後:
dsymtab = nil;\n\tUSED(dsymtab);
- 変更点:
dsymtab
変数がnil
に設定された後、使用されていなかったため、USED(dsymtab);
マクロを追加して警告を抑制しました。pgen.c
のケースと同様に、これは変数が意図的に設定されているが、現在のコードパスでは使用されないことを示すためのものです。
- 元のコード:
コアとなるコードの変更箇所
このコミットで変更された主要なファイルと行は以下の通りです。
src/cmd/6g/reg.c
: 1行変更 (671行目)src/cmd/gc/pgen.c
: 1行追加 (232行目)src/cmd/gc/plive.c
: 1行変更 (877行目)src/cmd/gc/walk.c
: 4行削除 (2886-2889行目, 2893-2896行目)src/cmd/ld/data.c
: 2行変更 (198行目, 230行目)src/cmd/ld/dwarf.c
: 1行削除 (1517行目)src/cmd/ld/elf.c
: 1行変更 (1507行目)src/cmd/ld/ldmacho.c
: 1行追加 (509行目)
コアとなるコードの解説
各変更箇所の具体的なコードと解説は以下の通りです。
src/cmd/6g/reg.c
--- a/src/cmd/6g/reg.c
+++ b/src/cmd/6g/reg.c
@@ -668,7 +668,7 @@ mkvar(Reg *r, Adr *a)
v->node = node;
if(debug['R'])
- print("bit=%2d et=%2E w=%d+%lld %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
+ print("bit=%2d et=%2E w=%lld+%lld %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
ostats.nvar++;
print
関数におけるo
変数のフォーマット指定子を%d
から%lld
に修正。o
がlong long
型であることを明示し、フォーマット不一致の警告を解消します。
src/cmd/gc/pgen.c
--- a/src/cmd/gc/pgen.c
+++ b/src/cmd/gc/pgen.c
@@ -232,6 +232,7 @@ compile(Node *fn)
if(0)
print("allocauto: %lld to %lld\\n", oldstksize, (vlong)stksize);
+ USED(oldstksize);
setlineno(curfn);
if((int64)stksize+maxarg > (1ULL<<31)) {
oldstksize
変数がif(0)
ブロック内でしか使用されていなかったため、「設定されたが使用されていない」警告が出ていました。USED(oldstksize);
を追加することで、この警告を抑制します。
src/cmd/gc/plive.c
--- a/src/cmd/gc/plive.c
+++ b/src/cmd/gc/plive.c
@@ -874,7 +874,7 @@ checkauto(Node *fn, Prog *p, Node *n, char *where)
print("D_AUTO '%s' not found: name is '%s' function is '%s' class is %d\\n", where, nname, fnname, n->class);
print("Here '%P'\\nlooking for node %p\\n", p, n);
for(ll = fn->dcl; ll != nil; ll = ll->next)
- print("node=%lx, node->class=%d\\n", (uintptr)ll->n, ll->n->class);
+ print("node=%p, node->class=%d\\n", (uintptr)ll->n, ll->n->class);
yyerror("checkauto: invariant lost");
}
ポインタll->n
の出力フォーマットを%lx
から%p
に修正。ポインタの正しい出力形式を使用することで、フォーマット不一致の警告を解消します。
src/cmd/gc/walk.c
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -2886,17 +2886,13 @@ sliceany(Node* n, NodeList **init)
if(isconst(cb, CTINT)) {
cbv = mpgetfix(cb->val.u.xval);
- if(cbv < 0 || cbv > bv) {
+ if(cbv < 0 || cbv > bv)
yyerror("slice index out of bounds");
- cbv = -1;
- }
}
if(isconst(hb, CTINT)) {
hbv = mpgetfix(hb->val.u.xval);
- if(hbv < 0 || hbv > bv) {
+ if(hbv < 0 || hbv > bv)
yyerror("slice index out of bounds");
- hbv = -1;
- }
}
if(isconst(lb, CTINT)) {
lbv = mpgetfix(lb->val.u.xval);
cbv = -1;
とhbv = -1;
の行を削除。これらの代入はyyerror
が呼び出された後に変数が使用されないため冗長であり、「設定されたが使用されていない」警告の原因となっていました。
src/cmd/ld/data.c
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -195,7 +195,7 @@ relocsym(LSym *s)
if(rs->type != SHOSTOBJ)
o += symaddr(rs);
} else {
- diag("unhandled pcrel relocation for %s", headtype);
+ diag("unhandled pcrel relocation for %s", headstring);
}
break;
}
@@ -227,7 +227,7 @@ relocsym(LSym *s)
o += symaddr(rs) - rs->sect->vaddr;
o -= r->off; // WTF?
} else {
- diag("unhandled pcrel relocation for %s", headtype);
+ diag("unhandled pcrel relocation for %s", headstring);
}
break;
}
diag
関数に渡す引数をheadtype
からheadstring
に修正。%s
フォーマット指定子に適切な文字列を渡すことで、フォーマット不一致の警告を解消します。
src/cmd/ld/dwarf.c
--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -1514,7 +1514,6 @@ writelines(void)
unitstart = -1;
headerend = -1;
- pc = 0;
epc = 0;
epcs = S;
lineo = cpos();
pc = 0;
の行を削除。pc
変数が初期化された後、使用されていなかったため、初期化自体を削除することで警告を解消します。
src/cmd/ld/elf.c
--- a/src/cmd/ld/elf.c
+++ b/src/cmd/ld/elf.c
@@ -1504,5 +1504,5 @@ elfobj:
a += elfwritebuildinfo();
}
if(a > ELFRESERVE)
- diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
+ diag("ELFRESERVE too small: %lld > %d", a, ELFRESERVE);
}
diag
関数におけるa
変数のフォーマット指定子を%d
から%lld
に修正。a
がlong long
型であることを明示し、フォーマット不一致の警告を解消します。
src/cmd/ld/ldmacho.c
--- a/src/cmd/ld/ldmacho.c
+++ b/src/cmd/ld/ldmacho.c
@@ -507,6 +507,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
c = nil;
symtab = nil;
dsymtab = nil;
+ USED(dsymtab);
for(i=0; i<ncmd; i++){
ty = e->e32(cmdp);
sz = e->e32(cmdp+4);
dsymtab
変数がnil
に設定された後、使用されていなかったため、「設定されたが使用されていない」警告が出ていました。USED(dsymtab);
を追加することで、この警告を抑制します。
関連リンク
- Go言語の公式リポジトリ: https://github.com/golang/go
- Goのコードレビューシステム (Gerrit): https://go.dev/cl/36740045 (元の変更リスト)
参考にした情報源リンク
- Plan 9 from Bell Labs: https://9p.io/plan9/
- Go言語のツールチェインに関するドキュメント (Goのバージョンによって内容が異なる場合があります): https://go.dev/doc/
- C言語の
printf
フォーマット指定子に関する一般的な情報源 (例: cppreference.com, cplusplus.comなど)