[インデックス 16640] ファイルの概要
このコミットは、Go言語のランタイムが依存するlib9
ライブラリにおいて、-Wconversion
コンパイラ警告を完全に回避するための変更を導入しています。具体的には、様々な場所で発生していた暗黙的な型変換による警告を、明示的な型キャストを追加することで解消しています。これにより、コードの堅牢性が向上し、将来的なコンパイラのバージョンアップや異なるプラットフォームでのビルドにおける潜在的な問題を未然に防ぐことを目的としています。
コミット
commit 7590e28d24d2dd50200808d2514656b6a440412f
Author: Ian Lance Taylor <iant@golang.org>
Date: Tue Jun 25 10:44:25 2013 -0700
lib9: avoid all -Wconversion warnings
Built after adding -Wconversion to the list of compiler
arguments used when building. I believe these are all OK
assuming we will not change the API. There is no effort to
detect overflow due to very long strings.
R=golang-dev, dave, rsc, r
CC=golang-dev
https://golang.org/cl/10195044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/7590e28d24d2dd50200808d2514656b6a440412f
元コミット内容
lib9: avoid all -Wconversion warnings
ビルド時に-Wconversion
をコンパイラ引数に追加した後にビルドしました。APIを変更しない限り、これらはすべて問題ないと考えています。非常に長い文字列によるオーバーフローを検出する努力はしていません。
変更の背景
このコミットの主な背景は、Go言語のビルドプロセスに-Wconversion
というコンパイラフラグが追加されたことにあります。-Wconversion
は、C/C++コンパイラ(特にGCCやClang)で利用できる警告フラグの一つで、暗黙的な型変換によってデータが失われる可能性のある箇所や、意図しない動作を引き起こす可能性のある箇所を検出します。
Go言語のランタイムや標準ライブラリの一部は、C言語で書かれたlib9
というライブラリに依存しています。lib9
は、Plan 9オペレーティングシステムから派生したユーティリティ関数群を提供するもので、Goの低レベルなシステムコールやファイル操作、文字列処理などに利用されています。
-Wconversion
フラグが導入されたことで、既存のlib9
コードベースに多数の警告が発生するようになりました。これらの警告は、必ずしもバグを示すものではありませんが、コードの意図を不明瞭にしたり、将来的なコンパイラの挙動変更によって問題を引き起こす可能性を秘めています。開発チームは、コードの品質と保守性を高めるため、これらの警告を解消することを決定しました。
コミットメッセージにある「APIを変更しない限り、これらはすべて問題ない」という記述は、これらの型キャストが既存のAPIのセマンティクスを変更するものではなく、単にコンパイラの警告を抑制するためのものであることを示唆しています。また、「非常に長い文字列によるオーバーフローを検出する努力はしていません」という注意書きは、型変換によって発生しうる数値のオーバーフロー(特にstrlen
の結果をint
にキャストする際など)については、このコミットの範囲外であることを明記しています。これは、文字列の長さがint
の最大値を超えるような極端なケースは、一般的なシステムでは発生しにくいという判断、またはその問題がこのコミットの目的ではないことを示しています。
前提知識の解説
1. lib9
とは
lib9
は、Go言語のプロジェクト内で使用されているC言語で書かれたライブラリ群です。その名の通り、Plan 9オペレーティングシステムに由来するユーティリティ関数やデータ構造を多く含んでいます。Go言語の初期の設計思想にはPlan 9の影響が強く見られ、特に低レベルなシステムプログラミングやファイルシステム操作において、lib9
の関数が利用されていました。
Goのランタイム(ガベージコレクション、スケジューラなど)や一部の標準ライブラリ(os
パッケージなど)は、直接C言語で書かれたコード(通常は_cgo_export.c
のようなファイルを通じてGoコードから呼び出される)や、lib9
のような外部Cライブラリに依存しています。これにより、GoはOSの低レベル機能にアクセスし、高性能な処理を実現しています。
2. -Wconversion
コンパイラフラグ
-Wconversion
は、GCCやClangといったC/C++コンパイラで利用できる警告オプションの一つです。このフラグを有効にすると、コンパイラは以下のような暗黙的な型変換(implicit type conversion)が発生する箇所で警告を発します。
- 縮小変換 (Narrowing Conversion): より広い範囲の値を表現できる型から、より狭い範囲の値を表現できる型への変換。例えば、
long
からint
への変換、unsigned int
からint
への変換など。この場合、元の値が変換先の型で表現できない範囲にあると、情報が失われる(オーバーフローやアンダーフロー)可能性があります。 - 符号付き/符号なし変換 (Signed/Unsigned Conversion): 符号付き整数型と符号なし整数型間の変換。特に、負の符号付き整数が符号なし整数に変換されると、大きな正の値として解釈されることがあります。
- 浮動小数点数変換 (Floating-point Conversion): 浮動小数点数型から整数型への変換。小数点以下の情報が切り捨てられます。
これらの警告は、プログラマが意図しないデータ損失や予期せぬ動作を防ぐために非常に有用です。例えば、size_t
(通常は符号なし整数型で、メモリのサイズや配列のインデックスを表す)の値をint
(符号付き整数型)に代入する場合、size_t
の値がint
の最大値を超えると、-Wconversion
が警告を発します。これは、特に大規模なデータ構造を扱う際に重要になります。
このコミットでは、これらの警告を解消するために、開発者が意図的に型変換を行っていることをコンパイラに明示的に伝える「キャスト(型変換演算子)」が多用されています。例えば、(int)strlen(s)
のように記述することで、strlen
が返すsize_t
型の値をint
型に変換することを明示しています。これにより、コンパイラは警告を発しなくなります。
技術的詳細
このコミットで行われている変更は、C言語における型変換の挙動と、それに対するコンパイラの警告メカニズムの理解に基づいています。
C言語では、異なる型の値が演算や代入で組み合わされる場合、コンパイラは自動的に型変換(暗黙的な型変換)を行います。この自動変換は便利な一方で、前述の-Wconversion
が警告するような、情報損失や意図しない解釈につながる可能性があります。
このコミットでは、主に以下の種類の型変換に対して明示的なキャストが追加されています。
-
size_t
からint
への変換:strlen
関数は文字列の長さをsize_t
型で返します。size_t
は通常、符号なし整数型であり、システムが扱える最大メモリサイズを表すのに十分な大きさを持っています。- しかし、多くのCコードでは、ループカウンタや配列のインデックスとして
int
型が使われることが多く、strlen
の結果をint
型の変数に代入する際に暗黙的な変換が発生します。 - 例:
sz += strlen(s)+1;
がsz += (int)strlen(s)+1;
に変更されています。これは、strlen
の戻り値がint
型に収まることを開発者が意図していることを示します。 - 同様に、
malloc
の引数やread
関数のサイズ引数など、size_t
を期待する箇所にint
型の値が渡される場合にもキャストが追加されています。例:malloc(sizeof(Dir)+nstr);
がmalloc(sizeof(Dir)+(size_t)nstr);
に変更されています。
-
long
やtime_t
からint
やulong
への変換:st->st_mtime
やst->st_atime
は通常time_t
型であり、これはシステムによってlong
やlong long
などの整数型にマップされます。- これらの値を
ulong
(符号なしロング)やint
に代入する際に、暗黙的な変換が発生していました。 - 例:
d->qid.vers = st->st_mtime + st->st_ctime;
がd->qid.vers = (ulong)(st->st_mtime + st->st_ctime);
に変更されています。 utimes
関数の引数であるtime_t
型へのキャストも同様です。
-
va_arg
の戻り値のキャスト:- 可変引数リストから値を取り出す
va_arg
マクロは、指定された型で値を返します。しかし、引数として渡された実際の型と、va_arg
で指定した型が異なる場合、またはその値が別の型に代入される場合に警告が発生することがあります。 - 例:
x[0] = va_arg(f->args, int);
がx[0] = (char)va_arg(f->args, int);
やx[0] = (Rune)va_arg(f->args, int);
に変更されています。これは、int
として受け取った値をchar
やRune
として扱うことを明示しています。
- 可変引数リストから値を取り出す
-
ポインタ演算の結果のキャスト:
- ポインタの減算の結果は、通常
ptrdiff_t
型(符号付き整数型)になります。これをint
型に代入する際に警告が発生していました。 - 例:
f->nfmt += rt - (Rune *)f->to;
がf->nfmt += (int)(rt - (Rune *)f->to);
に変更されています。
- ポインタの減算の結果は、通常
-
ビット演算における型の一貫性:
- フラグのクリアなど、ビット演算を行う際に、リテラル値の型と変数の型が異なる場合に警告が発生することがあります。
- 例:
f->flags &= ~FmtSharp;
がf->flags &= ~(ulong)FmtSharp;
に変更されています。これは、FmtSharp
が定義されているマクロや定数の型が、f->flags
の型(おそらくulong
)と一致しない場合に、~
演算の結果が意図しない型になることを防ぐためです。
これらの変更は、コードの機能自体を変更するものではなく、コンパイラに対する「この型変換は意図的なものであり、警告は不要である」という明確な指示を与えています。これにより、コンパイラは警告を発しなくなり、ビルドログがクリーンになります。クリーンなビルドログは、本当に重要な警告(例えば、未初期化変数や潜在的なバグ)を見つけやすくするために非常に重要です。
コアとなるコードの変更箇所
このコミットは、src/lib9
ディレクトリ以下の多数のCソースファイルにわたる広範な変更を含んでいます。主な変更は、様々なデータ型間の暗黙的な変換を明示的なキャストに置き換えることです。
以下に、代表的な変更箇所とそのパターンをいくつか示します。
src/lib9/_p9dir.c
--- a/src/lib9/_p9dir.c
+++ b/src/lib9/_p9dir.c
@@ -68,12 +68,12 @@ _p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *
*str += strlen(*str)+1;
}
}
- sz += strlen(s)+1;
+ sz += (int)strlen(s)+1;
/* user */
snprint(tmp, sizeof tmp, "%d", (int)st->st_uid);
s = tmp;
- sz += strlen(s)+1;
+ sz += (int)strlen(s)+1;
if(d){
if(*str+strlen(s)+1 > estr)
d->uid = "oops";
@@ -87,7 +87,7 @@ _p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *
/* group */
snprint(tmp, sizeof tmp, "%d", (int)st->st_gid);
s = tmp;
- sz += strlen(s)+1;
+ sz += (int)strlen(s)+1;
if(d){
if(*str + strlen(s)+1 > estr)
d->gid = "oops";
@@ -107,10 +107,10 @@ _p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *
d->qid.vers = st->st_gen;
#endif
if(d->qid.vers == 0)
- d->qid.vers = st->st_mtime + st->st_ctime;
+ d->qid.vers = (ulong)(st->st_mtime + st->st_ctime);
d->mode = st->st_mode&0777;
- d->atime = st->st_atime;
- d->mtime = st->st_mtime;
+ d->atime = (ulong)st->st_atime;
+ d->mtime = (ulong)st->st_mtime;
d->length = st->st_size;
if(S_ISDIR(st->st_mode)){
src/lib9/fmt/dofmt.c
--- a/src/lib9/fmt/dofmt.c
+++ b/src/lib9/fmt/dofmt.c
@@ -25,7 +25,7 @@ int
dofmt(Fmt *f, char *fmt)
{
Rune rune, *rt, *rs;
- int r;
+ Rune r;
char *t, *s;
int n, nfmt;
@@ -34,7 +34,7 @@ dofmt(Fmt *f, char *fmt)
if(f->runes){
rt = (Rune*)f->to;
rs = (Rune*)f->stop;
- while((r = *(uchar*)fmt) && r != '%'){
+ while((r = (Rune)*(uchar*)fmt) && r != '%'){
if(r < Runeself)
fmt++;
else{
@@ -44,7 +44,7 @@ dofmt(Fmt *f, char *fmt)
FMTRCHAR(f, rt, rs, r);
}
fmt++;
- f->nfmt += rt - (Rune *)f->to;
+ f->nfmt += (int)(rt - (Rune *)f->to);
f->to = rt;
if(!r)
return f->nfmt - nfmt;
@@ -52,7 +52,7 @@ dofmt(Fmt *f, char *fmt)
}else{
t = (char*)f->to;
s = (char*)f->stop;
- while((r = *(uchar*)fmt) && r != '%'){
+ while((r = (Rune)*(uchar*)fmt) && r != '%'){
if(r < Runeself){
FMTCHAR(f, t, s, r);
fmt++;
@@ -70,7 +70,7 @@ dofmt(Fmt *f, char *fmt)
}
}
fmt++;
- f->nfmt += t - (char *)f->to;
+ f->nfmt += (int)(t - (char *)f->to);
f->to = t;
if(!r)
return f->nfmt - nfmt;
@@ -87,9 +87,9 @@ void *
__fmtflush(Fmt *f, void *t, int len)
{
if(f->runes)
- f->nfmt += (Rune*)t - (Rune*)f->to;
+ f->nfmt += (int)((Rune*)t - (Rune*)f->to);
else
- f->nfmt += (char*)t - (char *)f->to;
+ f->nfmt += (int)((char*)t - (char *)f->to);
f->to = t;
if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
f->stop = f->to;
@@ -112,7 +112,7 @@ __fmtpad(Fmt *f, int n)
s = (char*)f->stop;
for(i = 0; i < n; i++)
FMTCHAR(f, t, s, ' ');
- f->nfmt += t - (char *)f->to;
+ f->nfmt += (int)(t - (char *)f->to);
f->to = t;
return 0;
}
@@ -127,7 +127,7 @@ __rfmtpad(Fmt *f, int n)
s = (Rune*)f->stop;
for(i = 0; i < n; i++)
FMTRCHAR(f, t, s, ' ');
- f->nfmt += t - (Rune *)f->to;
+ f->nfmt += (int)(t - (Rune *)f->to);
f->to = t;
return 0;
}
@@ -157,13 +157,13 @@ __fmtcpy(Fmt *f, const void *vm, int n, int sz)
r = *(uchar*)m;
if(r < Runeself)
m++;
- else if((me - m) >= UTFmax || fullrune(m, me-m))
+ else if((me - m) >= UTFmax || fullrune(m, (int)(me-m)))
m += chartorune(&r, m);
else
break;
FMTRCHAR(f, rt, rs, r);
}
- f->nfmt += rt - (Rune *)f->to;
+ f->nfmt += (int)(rt - (Rune *)f->to);
f->to = rt;
if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
return -1;
@@ -176,13 +176,13 @@ __fmtcpy(Fmt *f, const void *vm, int n, int sz)
r = *(uchar*)m;
if(r < Runeself)
m++;
- else if((me - m) >= UTFmax || fullrune(m, me-m))
+ else if((me - m) >= UTFmax || fullrune(m, (int)(me-m)))
m += chartorune(&r, m);
else
break;
FMTRUNE(f, t, s, r);
}
- f->nfmt += t - (char *)f->to;
+ f->nfmt += (int)(t - (char *)f->to);
f->to = t;
if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
return -1;
@@ -212,7 +212,7 @@ __fmtrcpy(Fmt *f, const void *vm, int n)
rs = (Rune*)f->stop;
for(me = m + n; m < me; m++)
FMTRCHAR(f, rt, rs, *m);
- f->nfmt += rt - (Rune *)f->to;
+ f->nfmt += (int)(rt - (Rune *)f->to);
f->to = rt;
if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
return -1;
@@ -225,7 +225,7 @@ __fmtrcpy(Fmt *f, const void *vm, int n)
r = *m;
FMTRUNE(f, t, s, r);
}
- f->nfmt += t - (char *)f->to;
+ f->nfmt += (int)(t - (char *)f->to);
f->to = t;
if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
return -1;
@@ -239,7 +239,7 @@ __charfmt(Fmt *f)
{
char x[1];
- x[0] = va_arg(f->args, int);
+ x[0] = (char)va_arg(f->args, int);
f->prec = 1;
return __fmtcpy(f, (const char*)x, 1, 1);
}
@@ -250,7 +250,7 @@ __runefmt(Fmt *f)
{
Rune x[1];
- x[0] = va_arg(f->args, int);
+ x[0] = (Rune)va_arg(f->args, int);
return __fmtrcpy(f, (const void*)x, 1);
}
@@ -278,7 +278,7 @@ fmtstrcpy(Fmt *f, char *s)
#endif
return __fmtcpy(f, s, j, i);
}
- return __fmtcpy(f, s, utflen(s), strlen(s));
+ return __fmtcpy(f, s, utflen(s), (int)strlen(s));
}
/* fmt out a null terminated utf string */
@@ -309,7 +309,7 @@ fmtrunestrcpy(Fmt *f, Rune *s)
}else{
for(e = s; *e; e++)
;
- n = e - s;
+ n = (int)(e - s);
}
return __fmtrcpy(f, s, n);
}
@@ -342,8 +342,8 @@ __ifmt(Fmt *f)
char buf[140], *p, *conv;
/* 140: for 64 bits of binary + 3-byte sep every 4 digits */
uvlong vu;
- ulong u;
- int neg, base, i, n, fl, w, isv;
+ ulong fl, u;
+ int neg, base, i, n, w, isv;
int ndig, len, excess, bytelen;
char *grouping;
char *thousands;
@@ -377,27 +377,27 @@ __ifmt(Fmt *f)
if(fl & FmtUnsigned)
vu = va_arg(f->args, uvlong);
else
- vu = va_arg(f->args, vlong);
+ vu = (uvlong)va_arg(f->args, vlong);
}else if(fl & FmtLong){
if(fl & FmtUnsigned)
u = va_arg(f->args, ulong);
else
- u = va_arg(f->args, long);
+ u = (ulong)va_arg(f->args, long);
}else if(fl & FmtByte){
if(fl & FmtUnsigned)
u = (uchar)va_arg(f->args, int);
else
- u = (char)va_arg(f->args, int);
+ u = (uchar)(char)va_arg(f->args, int);
}else if(fl & FmtShort){
if(fl & FmtUnsigned)
u = (ushort)va_arg(f->args, int);
else
- u = (short)va_arg(f->args, int);
+ u = (ushort)(short)va_arg(f->args, int);
}else{
if(fl & FmtUnsigned)
u = va_arg(f->args, uint);
else
- u = va_arg(f->args, int);
+ u = (uint)va_arg(f->args, int);
}
conv = "0123456789abcdef";
grouping = "\4"; /* for hex, octal etc. (undefined by spec but nice) */
@@ -428,10 +428,10 @@ __ifmt(Fmt *f)
}
if(!(fl & FmtUnsigned)){
if(isv && (vlong)vu < 0){
- vu = -(vlong)vu;
+ vu = (uvlong)-(vlong)vu;
neg = 1;
}else if(!isv && (long)u < 0){
- u = -(long)u;
+ u = (ulong)-(long)u;
neg = 1;
}
}
@@ -440,11 +440,11 @@ __ifmt(Fmt *f)
excess = 0; /* number of bytes > number runes */
ndig = 0;
len = utflen(thousands);
- bytelen = strlen(thousands);
+ bytelen = (int)strlen(thousands);
if(isv){
while(vu){
- i = vu % base;
- vu /= base;
+ i = (int)(vu % (uvlong)base);
+ vu /= (uvlong)base;
if((fl & FmtComma) && n % 4 == 3){
*p-- = ',';
n++;
@@ -453,15 +453,15 @@ __ifmt(Fmt *f)
n += len;
excess += bytelen - len;
p -= bytelen;
- memmove(p+1, thousands, bytelen);
+ memmove(p+1, thousands, (size_t)bytelen);
}
*p-- = conv[i];
n++;
}
}else{
while(u){
- i = u % base;
- u /= base;
+ i = (int)(u % (ulong)base);
+ u /= (ulong)base;
if((fl & FmtComma) && n % 4 == 3){
*p-- = ',';
n++;
@@ -470,7 +470,7 @@ __ifmt(Fmt *f)
n += len;
excess += bytelen - len;
p -= bytelen;
- memmove(p+1, thousands, bytelen);
+ memmove(p+1, thousands, (size_t)bytelen);
}
*p-- = conv[i];
n++;
@@ -496,14 +496,14 @@ __ifmt(Fmt *f)
* Zero values don't get 0x.
*/
if(f->r == 'x' || f->r == 'X')
- fl &= ~FmtSharp;
+ fl &= ~(ulong)FmtSharp;
}
for(w = f->prec; n < w && p > buf+3; n++){
if((fl & FmtApost) && __needsep(&ndig, &grouping)){
n += len;
excess += bytelen - len;
p -= bytelen;
- memmove(p+1, thousands, bytelen);
+ memmove(p+1, thousands, (size_t)bytelen);
}
*p-- = '0';
}
@@ -514,7 +514,7 @@ __ifmt(Fmt *f)
n += 2;
else if(base == 8){
if(p[1] == '0')
- fl &= ~FmtSharp;
+ fl &= ~(ulong)FmtSharp;
else
n++;
}
@@ -528,15 +528,15 @@ __ifmt(Fmt *f)
n += len;
excess += bytelen - len;
p -= bytelen;
- memmove(p+1, thousands, bytelen);
+ memmove(p+1, thousands, (size_t)bytelen);
}
*p-- = '0';
}
- f->flags &= ~FmtWidth;
+ f->flags &= ~(ulong)FmtWidth;
if(fl & FmtSharp){
if(base == 16)
- *p-- = f->r;
+ *p-- = (char)f->r;
if(base == 16 || base == 8)
*p-- = '0';
}
@@ -546,7 +546,7 @@ __ifmt(Fmt *f)
*p-- = '+';
else if(fl & FmtSpace)
*p-- = ' ';
- f->flags &= ~FmtPrec;
+ f->flags &= ~(ulong)FmtPrec;
return __fmtcpy(f, p + 1, n, n + excess);
}
@@ -563,9 +563,9 @@ __countfmt(Fmt *f)
}else if(fl & FmtLong){
*(long*)p = f->nfmt;
}else if(fl & FmtByte){
- *(char*)p = f->nfmt;
+ *(char*)p = (char)f->nfmt;
}else if(fl & FmtShort){
- *(short*)p = f->nfmt;
+ *(short*)p = (short)f->nfmt;
}else{
*(int*)p = f->nfmt;
}\n
コアとなるコードの解説
上記のコード変更は、C言語の型システムにおける暗黙的な型変換によって発生する-Wconversion
警告を解消するためのものです。それぞれの変更は、特定のコンテキストで発生する型ミスマッチを明示的に解決しています。
_p9dir.c
の変更
strlen(s)
の結果のキャスト:strlen
はsize_t
型(通常は符号なし整数)を返しますが、sz
変数がint
型であるため、sz += strlen(s)+1;
のような式で暗黙的な縮小変換が発生していました。(int)strlen(s)
と明示的にキャストすることで、strlen
の結果をint
として扱うことをコンパイラに伝えています。これは、文字列の長さがint
の最大値を超えることは稀であるという前提に基づいています。st_mtime
,st_ctime
,st_atime
のキャスト:struct stat
のタイムスタンプフィールド(st_mtime
,st_ctime
,st_atime
)はtime_t
型であり、これはシステムによって異なる整数型にマップされます。d->qid.vers
,d->atime
,d->mtime
といったフィールドがulong
型であるため、これらの代入時に暗黙的な変換が発生していました。(ulong)
へのキャストは、これらのタイムスタンプ値を符号なしロング整数として扱うことを明示しています。
fmt/dofmt.c
の変更
Rune r;
とint r;
の変更:dofmt
関数内で、文字を処理するための変数r
の型がint
からRune
に変更されています。Rune
はGo言語におけるUnicodeコードポイントを表す型であり、C言語の文脈では通常long
やint
のエイリアスとして定義されます。この変更は、文字コードをより正確に表現するため、および関連するキャストの必要性を生み出すために行われています。*(uchar*)fmt
のキャスト:while((r = *(uchar*)fmt) && r != '%')
のようなループで、char*
をuchar*
にキャストして文字を読み込み、それをRune
型の変数r
に代入しています。この際、*(uchar*)fmt
の結果がint
に昇格され、その後Rune
に暗黙的に変換されることで警告が発生していました。(Rune)*(uchar*)fmt
とすることで、この変換を明示しています。- ポインタ減算の結果のキャスト:
f->nfmt += rt - (Rune *)f->to;
のような式では、ポインタの減算の結果(ptrdiff_t
型)がf->nfmt
(おそらくint
型)に代入される際に暗黙的な変換が発生していました。(int)
へのキャストは、この変換を意図的なものとしています。 va_arg
の戻り値のキャスト:__charfmt
や__runefmt
関数で、va_arg
から取得したint
型の値をchar
やRune
型の配列要素に代入する際に警告が発生していました。(char)va_arg(f->args, int)
や(Rune)va_arg(f->args, int)
とすることで、この縮小変換を明示しています。strlen
の結果のキャスト:fmtstrcpy
関数で、utflen(s)
とstrlen(s)
の結果を__fmtcpy
に渡す際に、strlen(s)
の結果がint
にキャストされています。- 数値フォーマット関数の引数キャスト:
__ifmt
関数では、va_arg
から取得した様々な整数型(vlong
,long
,int
など)の値を、uvlong
やulong
,uchar
,ushort
,uint
といった符号なし型に代入する際に、明示的なキャストが追加されています。これは、符号付き/符号なし間の変換警告を解消するためです。 - ビット演算における型の一貫性:
fl &= ~FmtSharp;
のようなビット演算では、~FmtSharp
の結果の型がfl
の型(ulong
)と異なる場合に警告が発生していました。fl &= ~(ulong)FmtSharp;
とすることで、~
演算の結果をulong
として扱うことを明示し、型の一貫性を保っています。
これらの変更は、コードの動作を変更することなく、コンパイラの警告を抑制し、コードの意図をより明確にするための「クリーンアップ」作業です。これにより、開発者は本当に重要な警告に集中できるようになります。
関連リンク
- Go言語の公式リポジトリ: https://github.com/golang/go
- Go言語のコードレビューシステム (Gerrit): https://go.dev/cl/
- Plan 9 from Bell Labs: https://9p.io/plan9/
参考にした情報源リンク
- GCCの警告オプションに関するドキュメント: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html (特に
-Wconversion
のセクション) - C言語の型変換に関する一般的な情報源 (例: C Standard Library documentation, C programming tutorials)
- Go言語の内部構造に関するブログ記事やドキュメント (例: Go runtime source code analysis)
- Plan 9の歴史と影響に関する情報源 (例: Wikipedia, academic papers)