Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 18062] ファイルの概要

このコミットは、Goコンパイラ(cmd/6gcmd/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種類に分類されます。

  1. フォーマット文字列の不一致 (format mismatch): print関数(Plan 9 Cの標準出力関数)のフォーマット指定子と、対応する引数の型が一致していないために発生する警告。例えば、long long型の値を%d(int型用)で出力しようとしたり、ポインタを%lx(unsigned longの16進数用)で出力しようとしたりするケースです。
  2. 設定されたが使用されていない変数 (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言語のフォーマット指定子

printfprintのような関数では、出力するデータの型に合わせて適切なフォーマット指定子を使用する必要があります。

  • %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に変更しました。これは、olong 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->nuintptrにキャストして出力する際のフォーマットを%lxから%pに変更しました。%lxunsigned 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に変更しました。along 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に修正。olong 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に修正。along 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);を追加することで、この警告を抑制します。

関連リンク

参考にした情報源リンク

  • Plan 9 from Bell Labs: https://9p.io/plan9/
  • Go言語のツールチェインに関するドキュメント (Goのバージョンによって内容が異なる場合があります): https://go.dev/doc/
  • C言語のprintfフォーマット指定子に関する一般的な情報源 (例: cppreference.com, cplusplus.comなど)