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

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

このコミットは、Go言語のテストスイートにおいて、コンパイラが生成するエラーメッセージの期待値を更新するものです。特に、Goの公式コンパイラ(gc)とGCCベースのGoコンパイラ(gccgo)の間でエラーメッセージの整合性を高めることを目的としています。これにより、両コンパイラが不正なコードに対して同様の、かつ期待されるエラーを報告するようにテストが調整されます。

コミット

commit 6ed800c01d0587413b9d103ea939f406e5e85efc
Author: Ian Lance Taylor <iant@golang.org>
Date:   Fri Sep 28 08:30:30 2012 -0700

    test: match gccgo error messages
    
    const1.go:31:12: error: integer constant overflow
    const1.go:31:12: error: integer constant overflow
    const1.go:33:12: error: integer constant overflow
    const1.go:33:12: error: integer constant overflow
    const1.go:34:14: error: integer constant overflow
    const1.go:35:17: error: integer constant overflow
    const1.go:35:17: error: integer constant overflow
    const1.go:35:17: error: integer constant overflow
    const1.go:35:17: error: integer constant overflow
    const1.go:35:17: error: integer constant overflow
    const1.go:36:19: error: integer constant overflow
    const1.go:37:15: error: integer constant overflow
    const1.go:37:15: error: integer constant overflow
    const1.go:37:24: error: integer constant overflow
    const1.go:37:15: error: integer constant overflow
    const1.go:37:15: error: integer constant overflow
    const1.go:37:15: error: integer constant overflow
    const1.go:37:24: error: integer constant overflow
    const1.go:37:15: error: integer constant overflow
    const1.go:38:12: error: integer constant overflow
    const1.go:38:12: error: integer constant overflow
    const1.go:38:12: error: integer constant overflow
    const1.go:38:12: error: integer constant overflow
    const1.go:41:20: error: integer constant overflow
    const1.go:41:20: error: integer constant overflow
    const1.go:42:20: error: integer constant overflow
    const1.go:42:20: error: integer constant overflow
    const1.go:44:28: error: integer constant overflow
    const1.go:44:28: error: integer constant overflow
    const1.go:45:14: error: integer constant overflow
    const1.go:49:14: error: integer constant overflow
    const1.go:50:14: error: integer constant overflow
    const1.go:51:14: error: integer constant overflow
    const1.go:54:23: error: integer constant overflow
    const1.go:54:23: error: integer constant overflow
    const1.go:54:23: error: integer constant overflow
    const1.go:54:23: error: integer constant overflow
    const1.go:56:14: error: integer constant overflow
    const1.go:57:24: error: integer constant overflow
    const1.go:57:24: error: integer constant overflow
    const1.go:58:24: error: integer constant overflow
    const1.go:58:24: error: integer constant overflow
    const1.go:59:22: error: integer constant overflow
    const1.go:59:22: error: integer constant overflow
    const1.go:61:24: error: integer constant overflow
    const1.go:62:20: error: division by zero
    const1.go:65:19: error: floating point constant overflow
    const1.go:65:19: error: floating point constant overflow
    const1.go:66:28: error: floating point constant overflow
    const1.go:66:28: error: floating point constant overflow
    const1.go:67:19: error: floating point constant overflow
    const1.go:67:19: error: floating point constant overflow
    const1.go:68:19: error: division by zero
    const1.go:33:14: error: integer constant overflow
    const1.go:35:19: error: integer constant overflow
    const1.go:42:22: error: integer constant overflow
    const1.go:53:17: error: integer constant overflow
    const1.go:55:14: error: integer constant overflow
    const1.go:59:24: error: integer constant overflow
    const1.go:69:20: error: expected integer type
    const1.go:75:4: error: argument 1 has incompatible type (cannot use type int8 as type int)
    const1.go:76:4: error: argument 1 has incompatible type (cannot use type int8 as type int)
    const1.go:77:4: error: argument 1 has incompatible type (cannot use type uint8 as type int)
    const1.go:79:4: error: argument 1 has incompatible type (cannot use type float32 as type int)
    const1.go:80:4: error: argument 1 has incompatible type (cannot use type float64 as type int)
    const1.go:81:4: error: floating point constant truncated to integer
    const1.go:83:4: error: argument 1 has incompatible type (cannot use type float64 as type int)
    const1.go:84:4: error: argument 1 has incompatible type (cannot use type string as type int)
    const1.go:85:4: error: argument 1 has incompatible type (cannot use type bool as type int)
    const1.go:88:7: error: const initializer cannot be nil
    
    const2.go:14:8: error: expected ‘=’
    
    const5.go:27:7: error: expression is not constant
    const5.go:28:7: error: expression is not constant
    const5.go:30:7: error: expression is not constant
    const5.go:31:7: error: expression is not constant
    
    ddd1.go:57:23: error: invalid use of ‘...’ in type conversion
    ddd1.go:59:6: error: invalid use of ‘...’ in type conversion
    ddd1.go:60:12: error: use of ‘[...]’ outside of array literal
    ddd1.go:21:15: error: argument 1 has incompatible type
    ddd1.go:22:10: error: argument 1 has incompatible type
    ddd1.go:30:6: error: invalid use of ‘...’ with non-slice
    ddd1.go:30:6: error: invalid use of ‘...’ with non-slice
    ddd1.go:46:2: error: invalid use of %<...%> with builtin function
    ddd1.go:47:2: error: invalid use of %<...%> with builtin function
    ddd1.go:49:2: error: invalid use of %<...%> with builtin function
    ddd1.go:50:6: error: invalid use of %<...%> with builtin function
    ddd1.go:51:6: error: invalid use of %<...%> with builtin function
    ddd1.go:53:6: error: invalid use of %<...%> with builtin function
    ddd1.go:58:13: error: invalid use of %<...%> with builtin function
    ddd1.go:20:10: error: floating point constant truncated to integer
    ddd1.go:32:6: error: invalid use of ‘...’ calling non-variadic function
    
    declbad.go:20:3: error: variables redeclared but no variable is new
    declbad.go:38:3: error: variables redeclared but no variable is new
    declbad.go:44:3: error: variables redeclared but no variable is new
    declbad.go:51:3: error: variables redeclared but no variable is new
    declbad.go:57:3: error: variables redeclared but no variable is new
    declbad.go:63:3: error: variables redeclared but no variable is new
    declbad.go:26:3: error: incompatible types in assignment (cannot use type float32 as type int)
    declbad.go:32:3: error: incompatible types in assignment (cannot use type int as type float32)
    declbad.go:44:3: error: incompatible types in assignment (different number of results)
    
    fixedbugs/bug223.go:21:5: error: initialization expression for ‘m’ depends upon itself
    
    fixedbugs/bug412.go:10:2: error: duplicate field name ‘x’
    
    fixedbugs/bug413.go:11:5: error: initialization expression for ‘i’ depends upon itself
    
    fixedbugs/bug416.go:13:1: error: method ‘X’ redeclares struct field name
    
    fixedbugs/bug435.go:15:49: error: missing ‘)’
    fixedbugs/bug435.go:15:2: error: reference to undefined name ‘bar’
    
    fixedbugs/bug451.go:9:9: error: expected package
    
    typeswitch3.go:39:9: error: no new variables on left side of ‘:=’
    typeswitch3.go:24:2: error: impossible type switch case (type has no methods)
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/6560063

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/6ed800c01d0587413b9d103ea939f406e5e85efc

元コミット内容

このコミットの元々の内容は、Go言語のテストスイートが、gccgoコンパイラが生成するエラーメッセージと一致するように更新されたことを示しています。コミットメッセージには、const1.goconst2.goconst5.goddd1.godeclbad.gofixedbugs/bug223.gofixedbugs/bug412.gofixedbugs/bug413.gofixedbugs/bug416.gofixedbugs/bug435.gofixedbugs/bug451.gotypeswitch3.goといった複数のテストファイルで発生する具体的なエラーメッセージのリストが含まれています。これらのエラーメッセージは、gccgoが特定の不正なGoコードに対して出力するエラーの例であり、Goの標準コンパイラ(gc)のテストもこれらのエラーを適切に検出・報告するように調整されたことを意味します。

変更の背景

Go言語には主に2つの主要なコンパイラ実装があります。一つは公式のGoツールチェインに含まれるgc(Go compiler)であり、もう一つはGCC(GNU Compiler Collection)の一部として開発されているgccgoです。両コンパイラはGo言語の仕様に準拠していますが、エラーメッセージの文言や詳細度には差異が生じることがあります。

Goプロジェクトでは、異なるコンパイラ実装間での互換性と一貫性を非常に重視しています。特に、不正なコードに対するエラー報告は、開発者が問題を特定し修正するために不可欠な情報源です。もし同じ不正なコードに対してコンパイラによって全く異なるエラーメッセージが出力されると、開発者は混乱し、デバッグが困難になる可能性があります。

このコミットの背景には、gccgoが特定のGoコードに対して出力するエラーメッセージが、gcのテストスイートで期待されるエラーメッセージと完全に一致しないケースがあったという問題意識があります。テストスイートは、コンパイラが期待通りのエラーを報告するかどうかを検証する重要な役割を担っています。したがって、gccgoのエラーメッセージをテストスイートに反映させることで、両コンパイラの実装がより密接に連携し、Go言語の安定性と移植性を高めることが目的とされました。

前提知識の解説

Go言語のコンパイラ (gcgccgo)

  • gc (Go Compiler): Go言語の公式ツールチェインに同梱されている標準のコンパイラです。Go言語の設計思想と密接に連携して開発されており、高速なコンパイルと効率的な実行バイナリの生成に特化しています。Go言語の新しい機能は通常、まずgcに実装されます。
  • gccgo: GCCのフロントエンドとして実装されたGoコンパイラです。GCCの最適化バックエンドを利用できるため、特定のシナリオではgcよりも最適化されたコードを生成する可能性があります。gccgoはGCCのエコシステムに統合されており、他のGCCがサポートする言語との連携も可能です。

Go言語のテストにおけるエラーメッセージの検証

Go言語のテストスイートでは、コンパイラが特定のコードに対して期待されるエラーを正しく報告するかどうかを検証するために、特別なコメント構文が使用されます。

  • // ERROR "regexp": このコメントは、その行またはその周辺のコードがコンパイル時にエラーを発生させ、そのエラーメッセージが指定された正規表現(regexp)にマッチすることを期待することを示します。例えば、// ERROR "overflow"は、オーバーフローエラーが発生することを期待します。
  • // GC_ERROR "regexp": ERRORと同様ですが、これは特にgcコンパイラがエラーを発生させることを期待する場合に使用されます。gccgoのような他のコンパイラでは異なるエラーメッセージが出力されるか、あるいはエラーが発生しない可能性も考慮されます。

このコミットでは、既存のERRORコメントの正規表現を拡張したり、GC_ERRORに変更したりすることで、gccgoのエラーメッセージも許容範囲に含めるように調整しています。

Go言語における一般的なコンパイル時エラー

コミットメッセージに記載されているエラーメッセージは、Go言語でよく見られるコンパイル時エラーの典型例です。

  • integer constant overflow / floating point constant overflow: 整数型や浮動小数点型の定数が、その型で表現できる最大値を超えた場合に発生します。
  • division by zero: 定数式でゼロ除算が行われた場合に発生します。
  • argument 1 has incompatible type: 関数の引数の型が、期待される型と互換性がない場合に発生します。
  • expected integer type: 整数型が期待される場所で、異なる型が使用された場合に発生します。
  • expression is not constant: 定数式が期待される場所で、定数ではない式が使用された場合に発生します。
  • invalid use of ‘...’: 可変長引数(variadic function)の呼び出しやスライス展開(...演算子)の誤用に関するエラーです。
  • variables redeclared but no variable is new: 変数が再宣言されたが、新しい変数が導入されていない場合に発生します。Goでは、:=演算子で変数を宣言する際、少なくとも1つの新しい変数が左辺に必要です。
  • duplicate field name: 構造体内でフィールド名が重複している場合に発生します。
  • initialization loop / depends upon itself: 変数の初期化が循環参照になっている場合に発生します。
  • method 'X' redeclares struct field name: 構造体のフィールド名とメソッド名が重複している場合に発生します。
  • missing ')' / reference to undefined name: 構文エラーや未定義の識別子を参照した場合に発生します。
  • expected package: パッケージが期待される場所で、そうではないものが指定された場合に発生します。
  • no new variables on left side of ':=': :=演算子で新しい変数が宣言されていない場合に発生します。

これらのエラーは、Go言語の型システム、定数評価、スコープ規則、構文解析など、コンパイラの基本的な機能に関連しています。

技術的詳細

このコミットの技術的な核心は、Goコンパイラのテストフレームワークが、異なるコンパイラ実装(特にgcgccgo)からのエラーメッセージのわずかなバリエーションを許容するように適応することです。

コンパイラのエラーメッセージは、そのコンパイラの内部実装やエラー検出ロジックに強く依存します。例えば、あるコンパイラが「整数定数オーバーフロー」とだけ報告するのに対し、別のコンパイラは「整数定数オーバーフロー:値が大きすぎます」のように、より詳細な情報を含めることがあります。また、エラーの検出順序や、複数のエラーが同時に発生した場合の報告方法も異なる場合があります。

このコミットでは、主に以下の2つのアプローチでgccgoのエラーメッセージへの対応を行っています。

  1. 正規表現の拡張: 既存の// ERROR "..."コメント内の正規表現を、|(OR演算子)を使用して拡張しています。これにより、元のエラーメッセージとgccgoが生成する可能性のある代替のエラーメッセージの両方を許容するようにテストが変更されます。

    • 例: // ERROR "floating-point % operation"// ERROR "floating-point % operation|expected integer type" に変更されることで、gccgoが「expected integer type」というメッセージを出力した場合でもテストがパスするようになります。
    • 例: // ERROR "must be constant"// ERROR "must be constant|is not constant" に変更されることで、gccgoが「is not constant」というメッセージを出力した場合でもテストがパスするようになります。
    • 例: // ERROR "multiple-value"// ERROR "multiple-value|[.][.][.]" に変更されることで、...(可変長引数を示す)を含むエラーメッセージも許容されます。
  2. GC_ERRORへの変更: 一部のテストでは、// ERROR "..."// GC_ERROR "..."に変更しています。これは、特定のエラーがgcコンパイラに固有のものであるか、またはgccgoでは異なる振る舞いをするため、gcのみでそのエラーを期待するようにテストのスコープを限定する意図があります。

    • 例: const2.goでのconstant multiplication overflowconstant shift overflowのエラーがGC_ERRORに変更されています。これは、これらの特定のオーバーフロー検出がgcの内部ロジックに強く依存しており、gccgoでは異なる方法で処理される可能性があることを示唆しています。

これらの変更は、Go言語のテストスイートがより堅牢になり、異なるコンパイラ実装間での互換性テストがより効果的に行われるようにするための重要なステップです。これにより、Go言語のコードがどのコンパイラでビルドされても、一貫したエラー報告の振る舞いが期待できるようになります。

コアとなるコードの変更箇所

このコミットでは、Go言語のテストディレクトリ(test/)内の複数のファイルが変更されています。変更は主に、コンパイラのエラーメッセージを検証するためのコメント行に集中しています。

変更されたファイルと、その変更の概要は以下の通りです。

  • test/const1.go:

    --- a/test/const1.go
    +++ b/test/const1.go
    @@ -66,7 +66,7 @@ var (
     	c3 float64 = float64(Big) * Big // ERROR "overflow"
     	c4         = Big * Big          // ERROR "overflow"
     	c5         = Big / 0            // ERROR "division by zero"
    -	c6         = 1000 % 1e3         // ERROR "floating-point % operation"
    +	c6         = 1000 % 1e3         // ERROR "floating-point % operation|expected integer type"
     )
    

    floating-point % operationエラーに加えて、expected integer typeも許容するように正規表現が拡張されました。

  • test/const2.go:

    --- a/test/const2.go
    +++ b/test/const2.go
    @@ -16,6 +16,6 @@ const (
     
     const LargeA = 1000000000000000000
     const LargeB = LargeA * LargeA * LargeA
    -const LargeC = LargeB * LargeB * LargeB // ERROR "constant multiplication overflow"
    +const LargeC = LargeB * LargeB * LargeB // GC_ERROR "constant multiplication overflow"
     
    -const AlsoLargeA = LargeA << 400 << 400 >> 400 >> 400 // ERROR "constant shift overflow"
    +const AlsoLargeA = LargeA << 400 << 400 >> 400 >> 400 // GC_ERROR "constant shift overflow"
    

    ERRORGC_ERRORに変更され、これらのエラーがgcコンパイラに固有のものであることを示しています。

  • test/const5.go:

    --- a/test/const5.go
    +++ b/test/const5.go
    @@ -24,10 +24,10 @@ const (
     	n2 = len(m[""])
     	n3 = len(s[10])
     
    -	n4 = len(f())  // ERROR "must be constant"
    -	n5 = len(<-c) // ERROR "must be constant"
    +	n4 = len(f())  // ERROR "must be constant|is not constant"
    +	n5 = len(<-c) // ERROR "must be constant|is not constant"
     
    -	n6 = cap(f())  // ERROR "must be constant"
    -	n7 = cap(<-c) // ERROR "must be constant"
    +	n6 = cap(f())  // ERROR "must be constant|is not constant"
    +	n7 = cap(<-c) // ERROR "must be constant|is not constant"
     )
    

    must be constantエラーに加えて、is not constantも許容するように正規表現が拡張されました。

  • test/ddd1.go:

    --- a/test/ddd1.go
    +++ b/test/ddd1.go
    @@ -27,9 +27,9 @@ func tuple() (int, int, int) { return 1, 2, 3 }
     
     var (
     	_ = sum(tuple())
    -	_ = sum(tuple()...) // ERROR "multiple-value"
    +	_ = sum(tuple()...) // ERROR "multiple-value|[.][.][.]"
     	_ = sum3(tuple())
    -	_ = sum3(tuple()...) // ERROR "multiple-value" "not enough"
    +	_ = sum3(tuple()...) // ERROR "multiple-value|[.][.][.]" "not enough"
     )
    

    multiple-valueエラーに加えて、...を含むエラーメッセージも許容するように正規表現が拡張されました。

  • test/declbad.go:

    --- a/test/declbad.go
    +++ b/test/declbad.go
    @@ -41,8 +41,9 @@ func main() {
     	{
     		// multiline no new variables
     		i := f1
    -		i := func() int { // ERROR "redeclared|no new|incompatible"
    +		i := func() { // ERROR "redeclared|no new|incompatible"
     		}
    +		_ = i
     	}
     	{
     		// single redeclaration
    

    テストコード自体がわずかに変更され、_ = iが追加されましたが、エラーメッセージの正規表現自体は変更されていません。これは、テストの堅牢性を高めるための調整と考えられます。

  • test/fixedbugs/*.go (bug223, bug412, bug413, bug416, bug435, bug451): これらのファイルでは、既存のERRORコメントの正規表現に、|演算子を使ってgccgoが生成する可能性のある追加のフレーズ(例: |depends upon itself, |duplicate field name .x., |redeclares struct field name, |missing|undefined, |expected package)が追加されています。

  • test/typeswitch3.go:

    --- a/test/typeswitch3.go
    +++ b/test/typeswitch3.go
    @@ -36,7 +36,7 @@ func main(){
     	}
     	
     	// Issue 2827.
    -	switch _ := r.(type) {  // ERROR "invalid variable name _"
    +	switch _ := r.(type) {  // ERROR "invalid variable name _|no new variables"
     	}
     }
    

    invalid variable name _エラーに加えて、no new variablesも許容するように正規表現が拡張されました。

コアとなるコードの解説

これらの変更は、Go言語のテストスイートが、コンパイラのエラーメッセージのわずかなバリエーションに対応できるようにするためのものです。特に、gcgccgoという異なるコンパイラ実装間で、同じ不正なコードに対して類似したエラーが報告されることを保証するために行われました。

  • 正規表現の拡張 (|の使用): これは、最も一般的な変更パターンです。コンパイラAが「A」というエラーメッセージを出すのに対し、コンパイラBが「A (詳細)」や「B」というメッセージを出す場合、テストは両方のメッセージを認識できるようにする必要があります。|演算子を使うことで、テストは複数の可能なエラーメッセージパターンを受け入れることができます。これにより、gccgogcとは異なる、しかし意味的には同等なエラーメッセージを出力した場合でも、テストが失敗することなくパスするようになります。これは、コンパイラ間のエラー報告の一貫性を高めつつ、それぞれの実装の自由度をある程度保つための実用的なアプローチです。

  • GC_ERRORへの変更: 一部のエラーがGC_ERRORに変更されたのは、そのエラーがgcコンパイラの特定の最適化パスや内部的な振る舞いに起因するものであり、gccgoでは異なる方法で処理されるか、あるいは全く異なるエラーとして報告される可能性があるためです。GC_ERRORを使用することで、テストはgcに特化したエラーを検証しつつ、gccgoがそのエラーを報告しない場合でもテストが失敗しないようにします。これは、コンパイラ固有の振る舞いをテストするための重要な区別です。

これらの変更は、Go言語のコンパイラ開発において、異なる実装間での互換性とテストの網羅性を維持するための継続的な努力の一環です。これにより、Go言語のコードベースは、複数のコンパイラ環境でより安定して動作することが保証されます。

関連リンク

参考にした情報源リンク

  • Go言語のテストに関するドキュメント (Goのソースコード内のtestディレクトリのREADMEや、Goの公式ドキュメント):
    • Goのソースコード内のテストファイルのコメント規約に関する情報
    • Go言語のコンパイラ(gcgccgo)に関する情報
  • GCCGoの公式ドキュメントまたは関連情報:
  • Go言語の仕様書: https://go.dev/ref/spec (コンパイラが準拠すべき言語の振る舞いを定義)
  • Go言語のブログや開発者向け記事 (コンパイラの内部動作やテスト戦略に関するもの)