[インデックス 12023] ファイルの概要
本ドキュメントは、Go言語の公式リポジトリにおけるコミット 7737e19b15151f5a8578c77c5df99ce364b7d281
について、その背景、技術的詳細、および関連するコード変更を包括的に解説します。このコミットは、gccgo
コンパイラが正しく処理できなかった特定のGo言語のコードパターンに対するテストケースを追加することで、コンパイラの堅牢性を向上させることを目的としています。
コミット
このコミットは、Go言語のテストスイートに新たなテストケースを追加するものです。これらのテストケースは、以前 gccgo
コンパイラがコンパイルに失敗したり、誤ったエラーを報告したり、あるいはクラッシュしたりした特定のGoコードの振る舞いを検証するために設計されています。これにより、gccgo
の互換性と正確性を向上させることが意図されています。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/7737e19b15151f5a8578c77c5df99ce364b7d281
元コミット内容
commit 7737e19b15151f5a8578c77c5df99ce364b7d281
Author: Ian Lance Taylor <iant@golang.org>
Date: Fri Feb 17 17:52:05 2012 -0800
test: add some tests that gccgo failed to handle correctly
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5671090
---
test/fixedbugs/bug419.go | 17 +++++++++++++++++
test/fixedbugs/bug420.go | 14 ++++++++++++++\n test/fixedbugs/bug421.go | 17 +++++++++++++++++
test/fixedbugs/bug422.go | 11 +++++++++++
4 files changed, 59 insertions(+)
diff --git a/test/fixedbugs/bug419.go b/test/fixedbugs/bug419.go
new file mode 100644
index 0000000000..cfab404eb3
--- /dev/null
+++ b/test/fixedbugs/bug419.go
@@ -0,0 +1,17 @@
+// compile
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// Issue 1811.
+// gccgo failed to compile this.
+package p
+type E interface{}
+type I interface {
+ E
+ E
+}
diff --git a/test/fixedbugs/bug420.go b/test/fixedbugs/bug420.go
new file mode 100644
index 0000000000..02b4349d80
--- /dev/null
+++ b/fixedbugs/bug420.go
@@ -0,0 +1,14 @@
+// compile
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// Issue 1757.
+// gccgo failed to compile this.
+package main
+func main() {
+ (_) = 0
+}
diff --git a/test/fixedbugs/bug421.go b/test/fixedbugs/bug421.go
new file mode 100644
index 0000000000..1fe02375ab
--- /dev/null
+++ b/test/fixedbugs/bug421.go
@@ -0,0 +1,17 @@
+// errorcheck
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// Issue 1927.
+// gccgo failed to issue the first error below.
+package main
+func main() {
+ println(int(1) == uint(1)) // ERROR "types"
+ var x int = 1
+ var y uint = 1
+ println(x == y) // ERROR "types"
+}
diff --git a/test/fixedbugs/bug422.go b/test/fixedbugs/bug422.go
new file mode 100644
index 0000000000..6865fe4b63
--- /dev/null
+++ b/test/fixedbugs/bug422.go
@@ -0,0 +1,11 @@
+// compile
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// gccgo crashed compiling this file.
+package p
+var V = "a" > "b"
変更の背景
このコミットの主な背景は、Go言語の代替コンパイラである gccgo
の互換性と安定性の向上です。Go言語には公式のコンパイラ(gc
)がありますが、gccgo
はGCC(GNU Compiler Collection)をバックエンドとして利用するGoコンパイラであり、異なる最適化やプラットフォームサポートを提供することがあります。しかし、gccgo
は gc
と完全に同じ振る舞いを保証する必要があり、特にGo言語の仕様の微妙な点やエッジケースにおいて、gccgo
が誤ったコンパイル結果を出したり、コンパイラ自体がクラッシュしたりする問題が発生していました。
このコミットは、具体的に以下のGo Issue Trackerで報告されたバグに対応するテストケースを追加することで、これらの問題を浮き彫りにし、gccgo
の修正を促すことを目的としています。
- Issue 1811: インターフェースの埋め込みに関する
gccgo
のコンパイルエラー。 - Issue 1757: 空白識別子
_
の使用に関するgccgo
のコンパイルエラー。 - Issue 1927: 異なる数値型間の比較における型エラーの検出に関する
gccgo
の問題。 - 特定のクラッシュ: 文字列の比較における
gccgo
のクラッシュ。
これらのテストケースを追加することで、Go言語のテストスイートがより包括的になり、将来的に gccgo
やその他のGoコンパイラがGo言語の仕様に厳密に準拠していることを確認できるようになります。
前提知識の解説
Go言語のインターフェース
Go言語のインターフェースは、メソッドのシグネチャの集合を定義する型です。Goのインターフェースは、JavaやC++のような他の言語のインターフェースとは異なり、暗黙的に実装されます。つまり、ある型がインターフェースで定義されたすべてのメソッドを実装していれば、その型はそのインターフェースを満たしていると見なされます。
インターフェースは、他のインターフェースを埋め込むことができます。これにより、複数のインターフェースのメソッドセットを結合し、より大きなインターフェースを形成することが可能です。例えば、io.Reader
と io.Writer
を埋め込んだ io.ReadWriter
インターフェースのように、既存のインターフェースを再利用して新しいインターフェースを構築できます。
空白識別子 _
(Blank Identifier)
Go言語の空白識別子 _
は、値を破棄するために使用される特別な識別子です。これは、変数を宣言したがその値を使用しない場合や、関数の戻り値の一部を無視したい場合などに利用されます。例えば、_, err := someFunc()
のように、エラーだけを処理し、他の戻り値を無視する際に頻繁に用いられます。空白識別子に値を代入しても、その値はどこにも保存されず、コンパイラは未使用変数に関するエラーを報告しません。
Go言語の型システムと型の比較
Go言語は静的型付け言語であり、厳格な型システムを持っています。異なる型の値は、明示的な型変換(キャスト)なしには直接比較できないことが一般的です。特に、符号付き整数型(int
)と符号なし整数型(uint
)のような異なる数値型は、たとえ値が同じであっても、直接比較すると型エラーとなることがあります。これは、予期せぬ挙動やオーバーフローを防ぐためのGo言語の設計思想に基づいています。
gccgo
と gc
コンパイラ
Go言語には主に二つの主要なコンパイラ実装が存在します。
gc
(Go Compiler): これはGo言語の公式かつ標準的なコンパイラであり、Go言語のソースコードから実行可能なバイナリを生成します。Goチームによって開発・保守されており、Go言語の最新の機能や最適化が最初に実装される場所です。gccgo
: これはGCC(GNU Compiler Collection)の一部として実装されたGoコンパイラです。gccgo
はGo言語のフロントエンドを持ち、GCCのバックエンドを利用してコードを生成します。これにより、GCCがサポートする多様なアーキテクチャや最適化を利用できるという利点があります。しかし、gc
とは異なる実装であるため、Go言語の仕様の解釈や実装の詳細において、gc
とは異なる振る舞いをすることが稀にあります。このコミットで修正されるようなバグは、まさにgccgo
がGo言語の仕様に完全に準拠していなかったケースを示しています。
Go言語のテストフレームワーク
Go言語には、標準ライブラリに組み込まれた軽量なテストフレームワーク testing
パッケージがあります。テストファイルは通常、テスト対象のGoファイルと同じディレクトリに _test.go
というサフィックスを付けて配置されます。テスト関数は Test
で始まり、*testing.T
型の引数を取ります。
このコミットで追加されたテストファイルには、// compile
や // errorcheck
といったコメントが含まれています。これらはGo言語のテストスイートにおける特別なディレクティブであり、テストの意図を示します。
// compile
: このファイルがコンパイル可能であることをテストします。コンパイルエラーが発生した場合、テストは失敗します。// errorcheck
: このファイルがコンパイル時に特定のコンパイルエラーを発生させることをテストします。コメントに// ERROR "message"
の形式で期待されるエラーメッセージが記述されており、コンパイラがそのエラーを報告しない場合、テストは失敗します。
技術的詳細
このコミットは、gccgo
コンパイラがGo言語の特定の言語機能やセマンティクスを誤って解釈または処理していた問題に対処するためのものです。それぞれの bugXXX.go
ファイルは、異なる種類の gccgo
の問題を浮き彫りにします。
test/fixedbugs/bug419.go
(Issue 1811)
このテストケースは、Go言語のインターフェースの埋め込みに関する gccgo
の問題を扱っています。
package p
type E interface{}
type I interface {
E
E
}
Go言語の仕様では、インターフェースは同じインターフェースを複数回埋め込むことができます。これは冗長ではありますが、文法的に有効であり、コンパイルエラーとなるべきではありません。E
インターフェースは空のインターフェース(任意の型を受け入れる)であり、I
インターフェースは E
を二回埋め込んでいます。gccgo
はこのコードをコンパイルできなかったと報告されています。これは gccgo
がインターフェースの埋め込み、特に重複する埋め込みの処理において、Go言語の仕様に完全に準拠していなかったことを示唆しています。
test/fixedbugs/bug420.go
(Issue 1757)
このテストケースは、Go言語の空白識別子 _
の使用に関する gccgo
の問題を扱っています。
package main
func main() {
(_) = 0
}
Go言語では、空白識別子 _
は変数を宣言せずに値を破棄するために使用されます。しかし、このテストケースのように、(_)
のように括弧で囲んで空白識別子に値を代入しようとすると、これは文法的に無効な操作です。Go言語のコンパイラはこのようなコードに対してコンパイルエラーを報告すべきです。gccgo
はこの無効なコードをコンパイルできなかったと報告されており、これは gccgo
が空白識別子の不正な使用パターンを正しく検出できなかったか、あるいはその処理中に内部エラーが発生したことを示しています。
test/fixedbugs/bug421.go
(Issue 1927)
このテストケースは、異なる数値型間の比較における型エラーの検出に関する gccgo
の問題を扱っています。
package main
func main() {
println(int(1) == uint(1)) // ERROR "types"
var x int = 1
var y uint = 1
println(x == y) // ERROR "types"
}
Go言語では、int
と uint
のような異なる数値型は、たとえ値が同じであっても、直接比較することはできません。これは型安全性を保証するためのGoの設計原則です。このコードは、int
と uint
の値を直接比較しようとしているため、コンパイル時に型エラーを発生させるべきです。コメント // ERROR "types"
は、コンパイラが「types」というキーワードを含むエラーメッセージを報告することを期待していることを示しています。gccgo
は最初の比較 int(1) == uint(1)
に対してこのエラーを報告できなかったとされており、これは gccgo
がGo言語の型システムにおける厳密な比較規則を正しく適用できていなかったことを示しています。
test/fixedbugs/bug422.go
このテストケースは、文字列の比較における gccgo
のクラッシュに関する問題を扱っています。
package p
var V = "a" > "b"
Go言語では、文字列は辞書順で比較できます。"a" > "b"
という比較は、"a"
が "b"
よりも辞書順で大きいかどうかを評価します。この式は有効なGo言語のコードであり、コンパイル時に false
というブール値に評価されるべきです。しかし、gccgo
はこのファイルをコンパイルする際にクラッシュしたと報告されています。これは gccgo
が文字列比較の内部処理において、特定の条件下で未定義の動作やメモリ破損を引き起こすバグを抱えていたことを示唆しています。
コアとなるコードの変更箇所
このコミットでは、既存のコードの変更は行われず、Go言語のテストスイートに以下の4つの新しいファイルが追加されています。
test/fixedbugs/bug419.go
test/fixedbugs/bug420.go
test/fixedbugs/bug421.go
test/fixedbugs/bug422.go
これらのファイルはすべて test/fixedbugs/
ディレクトリに追加されており、これは特定のバグを修正するために追加されたテストケースを格納するための慣例的な場所です。
コアとなるコードの解説
test/fixedbugs/bug419.go
// compile
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Issue 1811.
// gccgo failed to compile this.
package p
type E interface{}
type I interface {
E
E
}
このテストは、gccgo
がインターフェースの重複埋め込みを正しく処理できることを確認します。E
は空のインターフェースであり、I
は E
を2回埋め込んでいます。Go言語の仕様ではこれは有効な構文であり、コンパイルエラーになるべきではありません。// compile
ディレクティブは、このファイルがエラーなくコンパイルされることを期待していることを示します。
test/fixedbugs/bug420.go
// compile
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Issue 1757.
// gccgo failed to compile this.
package main
func main() {
(_) = 0
}
このテストは、gccgo
が (_)
のような不正な空白識別子の使用を正しく検出できることを確認します。Go言語では、空白識別子 _
は値を破棄するために使用されますが、(_)
のように括弧で囲んで代入の左辺に置くことは文法的に許可されていません。このコードはコンパイルエラーになるべきです。// compile
ディレクティブは、このファイルがコンパイルエラーになることを期待していることを示します(ただし、このテストの目的は gccgo
がこの不正なコードをコンパイルしようとして失敗したという事実を捉えることです)。
test/fixedbugs/bug421.go
// errorcheck
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Issue 1927.
// gccgo failed to issue the first error below.
package main
func main() {
println(int(1) == uint(1)) // ERROR "types"
var x int = 1
var y uint = 1
println(x == y) // ERROR "types"
}
このテストは、gccgo
が異なる数値型(int
と uint
)間の直接比較に対して適切な型エラーを報告できることを確認します。Go言語では、これらの比較は型エラーとなるべきです。// errorcheck
ディレクティブと // ERROR "types"
コメントは、コンパイラが指定されたエラーメッセージを報告することを期待していることを示します。特に、gccgo
が最初の比較 int(1) == uint(1)
に対してエラーを報告できなかったという問題が指摘されています。
test/fixedbugs/bug422.go
// compile
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// gccgo crashed compiling this file.
package p
var V = "a" > "b"
このテストは、gccgo
が文字列の比較を正しく処理できることを確認します。Go言語では文字列は辞書順で比較可能であり、"a" > "b"
は有効な式です。この式は false
に評価されるべきです。// compile
ディレクティブは、このファイルがエラーなくコンパイルされることを期待していることを示します。このテストのコメントは、以前 gccgo
がこのコードをコンパイルする際にクラッシュしたことを示しており、そのクラッシュが修正されたことを検証するためのものです。
関連リンク
- Go Issue 1811: https://github.com/golang/go/issues/1811
- Go Issue 1757: https://github.com/golang/go/issues/1757
- Go Issue 1927: https://github.com/golang/go/issues/1927
- Go Code Review 5671090: https://golang.org/cl/5671090
参考にした情報源リンク
- Go Programming Language Specification: https://go.dev/ref/spec
- The Go Blog: The Go Programming Language and Google: https://go.dev/blog/go-and-google
- GCC Wiki: GoFrontEnd: https://gcc.gnu.org/wiki/GoFrontEnd
- Go Testing Package Documentation: https://pkg.go.dev/testing
- Go Blank Identifier: https://go.dev/doc/effective_go#blank
- Go Interfaces: https://go.dev/doc/effective_go#interfaces
- Go Type Conversions: https://go.dev/ref/spec#Conversions
- Go Comparison Operators: https://go.dev/ref/spec#Comparison_operators
- Go String Comparison: https://go.dev/blog/strings
- Go Issue Tracker: https://github.com/golang/go/issues
- Go Code Review: https://go.dev/doc/contribute#code_reviews
- Go Test Directives (e.g.,
// compile
,// errorcheck
): Go言語のテストスイートの内部的な慣習であり、公式ドキュメントには明示的に記載されていないことが多いですが、Goのソースコード内のテストファイルで広く使用されています。