[インデックス 16645] ファイルの概要
このコミットは、Go言語のテストスイート内にある test/shift1.go
ファイルに対する変更です。具体的には、シフト演算に関する型エラーのテストにおいて、gccgo
コンパイラが生成するエラーメッセージも認識できるように、期待されるエラーメッセージのパターンを更新しています。これにより、gccgo
を使用した場合でもテストが正しくパスするようになります。
コミット
commit 1761e250117e9917c3927fec06475fe98651c564
Author: Ian Lance Taylor <iant@golang.org>
Date: Wed Jun 26 08:23:52 2013 -0700
test/shift1.go: recognize gccgo errors
R=golang-dev, remyoudompheng, iant
CC=golang-dev
https://golang.org/cl/10524045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/1761e250117e9917c3927fec06475fe98651c564
元コミット内容
test/shift1.go: recognize gccgo errors
R=golang-dev, remyoudompheng, iant
CC=golang-dev
https://golang.org/cl/10524045
変更の背景
Go言語には、公式のコンパイラである gc
(Go Compiler) の他に、GCC (GNU Compiler Collection) をバックエンドとして利用する gccgo
という別のコンパイラ実装が存在します。Go言語の仕様は一つですが、異なるコンパイラ実装は、エラーメッセージの文言や詳細において微妙な違いを生じさせることがあります。
test/shift1.go
は、Go言語のシフト演算に関する厳密な型チェックルールを検証するためのテストファイルです。Go言語では、シフト演算の左オペランドは整数型でなければならず、浮動小数点数型や複合型をシフトすることは許可されていません。また、シフト量も特定の制約を受けます。これらのルールに違反した場合、コンパイル時にエラーが発生することが期待されます。
このコミット以前は、test/shift1.go
内の // ERROR
コメントで指定されている期待されるエラーメッセージが、主に gc
コンパイラが生成するメッセージに特化していました。しかし、gccgo
が生成するエラーメッセージが gc
のものと完全に一致しない場合、gccgo
でテストを実行すると、本来エラーとして検出されるべき箇所がテスト失敗として報告されてしまう問題がありました。
この変更の背景には、Go言語のテストスイートが複数のコンパイラ実装(特に gc
と gccgo
)で一貫して動作し、両方のコンパイラがGo言語の仕様に準拠していることを確認できるようにするという目的があります。
前提知識の解説
Go言語のシフト演算
Go言語におけるシフト演算子 (<<
と >>
) は、ビット単位のシフト操作を行います。その仕様には以下の重要な制約があります。
- 左オペランドの型: シフト演算の左オペランドは、整数型(
int
,uint
,int8
,uint8
など)でなければなりません。浮動小数点数型(float32
,float64
)や複合型(complex64
,complex128
)を直接シフトすることはできません。 - 右オペランド(シフト量)の型: シフト量は符号なし整数型(
uint
,uint8
など)であるか、または型なし定数である必要があります。負のシフト量は許可されません。 - 型なし定数とシフト: Go言語には「型なし定数 (untyped constant)」という概念があります。これは、リテラル(例:
1
,1.0
,true
,"hello"
) が、その使用される文脈によって適切な型に推論されるまで特定の型を持たないというものです。シフト演算の左オペランドが型なし定数である場合、その定数はシフト演算の文脈で整数型に変換可能でなければなりません。例えば、1.0 << s
のような式では、1.0
は型なし浮動小数点数定数ですが、シフト演算の左オペランドとしては整数型が期待されるため、エラーとなります。 - コンパイル時エラー: これらのルールに違反するシフト演算は、コンパイル時にエラーとして検出されます。
gc
と gccgo
gc
(Go Compiler): Go言語の公式かつ主要なコンパイラです。Go言語のソースコードを直接機械語にコンパイルします。Go言語のリリースサイクルに合わせて開発され、Go言語の最新の機能や最適化が最初に実装されることが多いです。gccgo
: GCC (GNU Compiler Collection) のフロントエンドとしてGo言語をサポートするコンパイラです。Go言語のソースコードをGCCの中間表現に変換し、その後GCCのバックエンドが様々なアーキテクチャ向けの機械語を生成します。gccgo
はGCCのインフラストラクチャを利用するため、GCCがサポートする多くのプラットフォームや最適化の恩恵を受けることができます。しかし、エラーメッセージの生成ロジックはgc
とは独立しているため、同じGoの仕様違反に対しても異なる文言のエラーメッセージを出すことがあります。
// ERROR
コメント
Go言語のテストスイートでは、コンパイル時に特定のエラーが発生することを期待するテストケースで、ソースコードの該当行に // ERROR "expected error message"
のようなコメントを記述する慣習があります。テスト実行時、コンパイラがこの行で指定されたエラーメッセージを含むエラーを出力した場合、そのテストケースは成功とみなされます。このメカニズムにより、コンパイラがGo言語の仕様に準拠しているか、特にエラー検出の側面で正しく動作しているかを検証します。
このコミットでは、// ERROR
コメント内の期待されるエラーメッセージに |
(パイプ) を使用して複数のパターンを記述しています。これは正規表現のOR演算子のように機能し、指定された複数のエラーメッセージのいずれかが検出されればテストが成功することを意味します。例えば、// ERROR "invalid|shift of non-integer operand"
は、"invalid" または "shift of non-integer operand" のいずれかの文字列がエラーメッセージに含まれていれば良い、ということを示します。
技術的詳細
このコミットの技術的詳細は、test/shift1.go
ファイル内の // ERROR
コメントの変更に集約されます。変更の目的は、gc
と gccgo
の両方のコンパイラが生成する可能性のあるエラーメッセージをテストが認識できるようにすることです。
具体的には、多くの ERROR
コメントにおいて、既存のエラーメッセージに加えて、gccgo
が出力する可能性のある代替のエラーメッセージが |
で区切られて追加されています。
例:
-
e1 = g(2.0 << s) // ERROR "invalid" "as type interface"
がe1 = g(2.0 << s) // ERROR "invalid|shift of non-integer operand" "as type interface"
に変更されています。 これは、2.0
という浮動小数点数をシフトしようとしているため、Goの仕様に違反します。gc
は "invalid" のような一般的なエラーを出すかもしれませんが、gccgo
はより具体的な "shift of non-integer operand" というメッセージを出す可能性があります。この変更により、どちらのメッセージが出力されてもテストが成功するようになります。 -
_ = 1.<<s == 1. // ERROR "shift of type float64"
が_ = 1.<<s == 1. // ERROR "invalid|non-integer|shift of type float64"
に変更されています。 ここでも、1.
という浮動小数点数定数をシフトしようとしているためエラーです。gccgo
は "invalid" や "non-integer" といったキーワードを含むエラーメッセージを生成する可能性があるため、これらも許容するようにテストが更新されています。 -
_ = make([]int, 1.1<<s) // ERROR "1.1 truncated"
が_ = make([]int, 1.1<<s) // ERROR "non-integer|truncated"
に変更されています。make
関数の第二引数(長さ)は整数型である必要がありますが、1.1<<s
は浮動小数点数定数のシフトであり、整数に切り捨てられる(truncated)可能性があります。gccgo
はこの状況で "non-integer" というエラーメッセージを出す可能性があるため、これも追加されています。
これらの変更は、Go言語のコンパイラ実装が異なっても、言語仕様の違反に対するエラー検出の振る舞いが一貫していることを保証するための、テストスイートの堅牢性を高める作業の一環です。
コアとなるコードの変更箇所
変更は test/shift1.go
ファイルのみです。
--- a/test/shift1.go
+++ b/test/shift1.go
@@ -23,7 +23,7 @@ var (
// non-constant shift expressions
var (
- e1 = g(2.0 << s) // ERROR "invalid" "as type interface"
+ e1 = g(2.0 << s) // ERROR "invalid|shift of non-integer operand" "as type interface"
f1 = h(2 << s) // ERROR "invalid" "as type float64"
g1 int64 = 1.1 << s // ERROR "truncated"
)
@@ -39,12 +39,12 @@ var (
var (
// issues 4882, 4936.
- a3 = 1.0<<s + 0 // ERROR "invalid operation|shift of non-integer operand"
+ a3 = 1.0<<s + 0 // ERROR "invalid|shift of non-integer operand"
// issue 4937
- b3 = 1<<s + 1 + 1.0 // ERROR "invalid operation|shift of non-integer operand"
+ b3 = 1<<s + 1 + 1.0 // ERROR "invalid|shift of non-integer operand"
// issue 5014
- c3 = complex(1<<s, 0) // ERROR "shift of type float64"
- d3 int = complex(1<<s, 3) // ERROR "cannot use.*as type int" "shift of type float64"
+ c3 = complex(1<<s, 0) // ERROR "invalid|shift of type float64"
+ d3 int = complex(1<<s, 3) // ERROR "non-integer|cannot use.*as type int" "shift of type float64"
e3 = real(1 << s) // ERROR "invalid"
f3 = imag(1 << s) // ERROR "invalid"
)
@@ -61,60 +61,61 @@ func _() {
o = 1<<s == 2<<s // 1 and 2 have type int; o == true if ints are 32bits in size
// next test only fails on 32bit systems
// p = 1<<s == 1<<33 // illegal if ints are 32bits in size: 1 has type int, but 1<<33 overflows int
- u = 1.0 << s // ERROR "float64"
- u1 = 1.0<<s != 0 // ERROR "float64"
- u2 = 1<<s != 1.0 // ERROR "float64"
- v float32 = 1 << s // ERROR "float32"
+ u = 1.0 << s // ERROR "non-integer|float64"
+ u1 = 1.0<<s != 0 // ERROR "non-integer|float64"
+ u2 = 1<<s != 1.0 // ERROR "non-integer|float64"
+ v float32 = 1 << s // ERROR "non-integer|float32"
w int64 = 1.0 << 33 // 1.0<<33 is a constant shift expression
+ _, _, _, _, _, _, _, _, _, _ = j, k, m, n, o, u, u1, u2, v, w
)
}
// shifts in comparisons w/ untyped operands
var (
_ = 1<<s == 1
- _ = 1<<s == 1. // ERROR "shift of type float64"
- _ = 1.<<s == 1 // ERROR "shift of type float64"
- _ = 1.<<s == 1. // ERROR "shift of type float64"
+ _ = 1<<s == 1. // ERROR "invalid|shift of type float64"
+ _ = 1.<<s == 1 // ERROR "invalid|shift of type float64"
+ _ = 1.<<s == 1. // ERROR "invalid|non-integer|shift of type float64"
_ = 1<<s+1 == 1
- _ = 1<<s+1 == 1. // ERROR "shift of type float64"
- _ = 1<<s+1. == 1 // ERROR "shift of type float64"
- _ = 1<<s+1. == 1. // ERROR "shift of type float64"
- _ = 1.<<s+1 == 1 // ERROR "shift of type float64"
- _ = 1.<<s+1 == 1. // ERROR "shift of type float64"
- _ = 1.<<s+1. == 1 // ERROR "shift of type float64"
- _ = 1.<<s+1. == 1. // ERROR "shift of type float64"
+ _ = 1<<s+1 == 1. // ERROR "invalid|shift of type float64"
+ _ = 1<<s+1. == 1 // ERROR "invalid|shift of type float64"
+ _ = 1<<s+1. == 1. // ERROR "invalid|shift of type float64"
+ _ = 1.<<s+1 == 1 // ERROR "invalid|shift of type float64"
+ _ = 1.<<s+1 == 1. // ERROR "invalid|shift of type float64"
+ _ = 1.<<s+1. == 1 // ERROR "invalid|shift of type float64"
+ _ = 1.<<s+1. == 1. // ERROR "invalid|non-integer|shift of type float64"
_ = 1<<s == 1<<s
- _ = 1<<s == 1.<<s // ERROR "shift of type float64"
- _ = 1.<<s == 1<<s // ERROR "shift of type float64"
- _ = 1.<<s == 1.<<s // ERROR "shift of type float64"
+ _ = 1<<s == 1.<<s // ERROR "invalid|shift of type float64"
+ _ = 1.<<s == 1<<s // ERROR "invalid|shift of type float64"
+ _ = 1.<<s == 1.<<s // ERROR "invalid|non-integer|shift of type float64"
_ = 1<<s+1<<s == 1
- _ = 1<<s+1<<s == 1. // ERROR "shift of type float64"
- _ = 1<<s+1.<<s == 1 // ERROR "shift of type float64"
- _ = 1<<s+1.<<s == 1. // ERROR "shift of type float64"
- _ = 1.<<s+1<<s == 1 // ERROR "shift of type float64"
- _ = 1.<<s+1<<s == 1. // ERROR "shift of type float64"
- _ = 1.<<s+1.<<s == 1 // ERROR "shift of type float64"
- _ = 1.<<s+1.<<s == 1. // ERROR "shift of type float64"
+ _ = 1<<s+1<<s == 1. // ERROR "invalid|shift of type float64"
+ _ = 1<<s+1.<<s == 1 // ERROR "invalid|shift of type float64"
+ _ = 1<<s+1.<<s == 1. // ERROR "invalid|shift of type float64"
+ _ = 1.<<s+1<<s == 1 // ERROR "invalid|shift of type float64"
+ _ = 1.<<s+1<<s == 1. // ERROR "invalid|shift of type float64"
+ _ = 1.<<s+1.<<s == 1 // ERROR "invalid|shift of type float64"
+ _ = 1.<<s+1.<<s == 1. // ERROR "invalid|non-integer|shift of type float64"
_ = 1<<s+1<<s == 1<<s+1<<s
- _ = 1<<s+1<<s == 1<<s+1.<<s // ERROR "shift of type float64"
- _ = 1<<s+1<<s == 1.<<s+1<<s // ERROR "shift of type float64"
- _ = 1<<s+1<<s == 1.<<s+1.<<s // ERROR "shift of type float64"
- _ = 1<<s+1.<<s == 1<<s+1<<s // ERROR "shift of type float64"
- _ = 1<<s+1.<<s == 1<<s+1.<<s // ERROR "shift of type float64"
- _ = 1<<s+1.<<s == 1.<<s+1<<s // ERROR "shift of type float64"
- _ = 1<<s+1.<<s == 1.<<s+1.<<s // ERROR "shift of type float64"
- _ = 1.<<s+1<<s == 1<<s+1<<s // ERROR "shift of type float64"
- _ = 1.<<s+1<<s == 1<<s+1.<<s // ERROR "shift of type float64"
- _ = 1.<<s+1<<s == 1.<<s+1<<s // ERROR "shift of type float64"
- _ = 1.<<s+1<<s == 1.<<s+1.<<s // ERROR "shift of type float64"
- _ = 1.<<s+1.<<s == 1<<s+1<<s // ERROR "shift of type float64"
- _ = 1.<<s+1.<<s == 1<<s+1.<<s // ERROR "shift of type float64"
- _ = 1.<<s+1.<<s == 1.<<s+1<<s // ERROR "shift of type float64"
- _ = 1.<<s+1.<<s == 1.<<s+1.<<s // ERROR "shift of type float64"
+ _ = 1<<s+1<<s == 1<<s+1.<<s // ERROR "invalid|shift of type float64"
+ _ = 1<<s+1<<s == 1.<<s+1<<s // ERROR "invalid|shift of type float64"
+ _ = 1<<s+1<<s == 1.<<s+1.<<s // ERROR "invalid|shift of type float64"
+ _ = 1<<s+1.<<s == 1<<s+1<<s // ERROR "invalid|shift of type float64"
+ _ = 1<<s+1.<<s == 1<<s+1.<<s // ERROR "invalid|shift of type float64"
+ _ = 1<<s+1.<<s == 1.<<s+1<<s // ERROR "invalid|shift of type float64"
+ _ = 1<<s+1.<<s == 1.<<s+1.<<s // ERROR "invalid|non-integer|shift of type float64"
+ _ = 1.<<s+1<<s == 1<<s+1<<s // ERROR "invalid|shift of type float64"
+ _ = 1.<<s+1<<s == 1<<s+1.<<s // ERROR "invalid|shift of type float64"
+ _ = 1.<<s+1<<s == 1.<<s+1<<s // ERROR "invalid|shift of type float64"
+ _ = 1.<<s+1<<s == 1.<<s+1.<<s // ERROR "invalid|non-integer|shift of type float64"
+ _ = 1.<<s+1.<<s == 1<<s+1<<s // ERROR "invalid|shift of type float64"
+ _ = 1.<<s+1.<<s == 1<<s+1.<<s // ERROR "invalid|non-integer|shift of type float64"
+ _ = 1.<<s+1.<<s == 1.<<s+1<<s // ERROR "invalid|non-integer|shift of type float64"
+ _ = 1.<<s+1.<<s == 1.<<s+1.<<s // ERROR "invalid|non-integer|shift of type float64"
)
// shifts in comparisons w/ typed operands
@@ -122,21 +123,21 @@ var (
x int
_ = 1<<s == x
_ = 1.<<s == x
- _ = 1.1<<s == x // ERROR "1.1 truncated"
+ _ = 1.1<<s == x // ERROR "truncated"
_ = 1<<s+x == 1
_ = 1<<s+x == 1.
- _ = 1<<s+x == 1.1 // ERROR "1.1 truncated"
+ _ = 1<<s+x == 1.1 // ERROR "truncated"
_ = 1.<<s+x == 1
_ = 1.<<s+x == 1.
- _ = 1.<<s+x == 1.1 // ERROR "1.1 truncated"
- _ = 1.1<<s+x == 1 // ERROR "1.1 truncated"
- _ = 1.1<<s+x == 1. // ERROR "1.1 truncated"
- _ = 1.1<<s+x == 1.1 // ERROR "1.1 truncated"
+ _ = 1.<<s+x == 1.1 // ERROR "truncated"
+ _ = 1.1<<s+x == 1 // ERROR "truncated"
+ _ = 1.1<<s+x == 1. // ERROR "truncated"
+ _ = 1.1<<s+x == 1.1 // ERROR "truncated"
_ = 1<<s == x<<s
_ = 1.<<s == x<<s
- _ = 1.1<<s == x<<s // ERROR "1.1 truncated"
+ _ = 1.1<<s == x<<s // ERROR "truncated"
)
// shifts as operands in non-arithmetic operations and as arguments
@@ -146,43 +147,43 @@ func _() {
_ = a[1<<s]
_ = a[1.]
// For now, the spec disallows these. We may revisit past Go 1.1.
- _ = a[1.<<s] // ERROR "shift of type float64"
- _ = a[1.1<<s] // ERROR "shift of type float64"
+ _ = a[1.<<s] // ERROR "integer|shift of type float64"
+ _ = a[1.1<<s] // ERROR "integer|shift of type float64"
_ = make([]int, 1)
_ = make([]int, 1.)
_ = make([]int, 1.<<s)
- _ = make([]int, 1.1<<s) // ERROR "1.1 truncated"
+ _ = make([]int, 1.1<<s) // ERROR "non-integer|truncated"
_ = float32(1)
- _ = float32(1 << s) // ERROR "shift of type float32"
+ _ = float32(1 << s) // ERROR "non-integer|shift of type float32"
_ = float32(1.)
- _ = float32(1. << s) // ERROR "shift of type float32"
- _ = float32(1.1 << s) // ERROR "shift of type float32"
+ _ = float32(1. << s) // ERROR "non-integer|shift of type float32"
+ _ = float32(1.1 << s) // ERROR "non-integer|shift of type float32"
_ = append(a, 1<<s)
_ = append(a, 1.<<s)
- _ = append(a, 1.1<<s) // ERROR "1.1 truncated"
+ _ = append(a, 1.1<<s) // ERROR "truncated"
var b []float32
- _ = append(b, 1<<s) // ERROR "type float32"
- _ = append(b, 1.<<s) // ERROR "type float32"
- _ = append(b, 1.1<<s) // ERROR "type float32"
+ _ = append(b, 1<<s) // ERROR "non-integer|type float32"
+ _ = append(b, 1.<<s) // ERROR "non-integer|type float32"
+ _ = append(b, 1.1<<s) // ERROR "non-integer|type float32"
- _ = complex(1.<<s, 0) // ERROR "shift of type float64"
- _ = complex(1.1<<s, 0) // ERROR "shift of type float64"
- _ = complex(0, 1.<<s) // ERROR "shift of type float64"
- _ = complex(0, 1.1<<s) // ERROR "shift of type float64"
+ _ = complex(1.<<s, 0) // ERROR "non-integer|shift of type float64"
+ _ = complex(1.1<<s, 0) // ERROR "non-integer|shift of type float64"
+ _ = complex(0, 1.<<s) // ERROR "non-integer|shift of type float64"
+ _ = complex(0, 1.1<<s) // ERROR "non-integer|shift of type float64"
var a4 float64
var b4 int
- _ = complex(1<<s, a4) // ERROR "shift of type float64"
- _ = complex(1<<s, b4) // ERROR "invalid"
+ _ = complex(1<<s, a4) // ERROR "non-integer|shift of type float64"
+ _ = complex(1<<s, b4) // ERROR "invalid|non-integer|"
var m1 map[int]string
delete(m1, 1<<s)
delete(m1, 1.<<s)
- delete(m1, 1.1<<s) // ERROR "1.1 truncated|shift of type float64"
+ delete(m1, 1.1<<s) // ERROR "truncated|shift of type float64"
var m2 map[float32]string
delete(m2, 1<<s) // ERROR "invalid|cannot use 1 << s as type float32"
@@ -195,46 +196,46 @@ func _() {
var s uint
_ = 1 << (1 << s)
_ = 1 << (1. << s)
- _ = 1 << (1.1 << s) // ERROR "1.1 truncated"
- _ = 1. << (1 << s) // ERROR "shift of type float64"
- _ = 1. << (1. << s) // ERROR "shift of type float64"
- _ = 1.1 << (1.1 << s) // ERROR "invalid|1.1 truncated"
+ _ = 1 << (1.1 << s) // ERROR "non-integer|truncated"
+ _ = 1. << (1 << s) // ERROR "non-integer|shift of type float64"
+ _ = 1. << (1. << s) // ERROR "non-integer|shift of type float64"
+ _ = 1.1 << (1.1 << s) // ERROR "invalid|non-integer|truncated"
_ = (1 << s) << (1 << s)
_ = (1 << s) << (1. << s)
- _ = (1 << s) << (1.1 << s) // ERROR "1.1 truncated"
- _ = (1. << s) << (1 << s) // ERROR "shift of type float64"
- _ = (1. << s) << (1. << s) // ERROR "shift of type float64"
- _ = (1.1 << s) << (1.1 << s) // ERROR "invalid|1.1 truncated"
+ _ = (1 << s) << (1.1 << s) // ERROR "truncated"
+ _ = (1. << s) << (1 << s) // ERROR "non-integer|shift of type float64"
+ _ = (1. << s) << (1. << s) // ERROR "non-integer|shift of type float64"
+ _ = (1.1 << s) << (1.1 << s) // ERROR "invalid|non-integer|truncated"
var x int
x = 1 << (1 << s)
x = 1 << (1. << s)
- x = 1 << (1.1 << s) // ERROR "1.1 truncated"
+ x = 1 << (1.1 << s) // ERROR "truncated"
x = 1. << (1 << s)
x = 1. << (1. << s)
- x = 1.1 << (1.1 << s) // ERROR "1.1 truncated"
+ x = 1.1 << (1.1 << s) // ERROR "truncated"
x = (1 << s) << (1 << s)
x = (1 << s) << (1. << s)
- x = (1 << s) << (1.1 << s) // ERROR "1.1 truncated"
+ x = (1 << s) << (1.1 << s) // ERROR "truncated"
x = (1. << s) << (1 << s)
x = (1. << s) << (1. << s)
- x = (1.1 << s) << (1.1 << s) // ERROR "1.1 truncated"
+ x = (1.1 << s) << (1.1 << s) // ERROR "truncated"
var y float32
- y = 1 << (1 << s) // ERROR "type float32"
- y = 1 << (1. << s) // ERROR "type float32"
- y = 1 << (1.1 << s) // ERROR "invalid|1.1 truncated|float32"
- y = 1. << (1 << s) // ERROR "type float32"
- y = 1. << (1. << s) // ERROR "type float32"
- y = 1.1 << (1.1 << s) // ERROR "invalid|1.1 truncated|float32"
+ y = 1 << (1 << s) // ERROR "non-integer|type float32"
+ y = 1 << (1. << s) // ERROR "non-integer|type float32"
+ y = 1 << (1.1 << s) // ERROR "invalid|truncated|float32"
+ y = 1. << (1 << s) // ERROR "non-integer|type float32"
+ y = 1. << (1. << s) // ERROR "non-integer|type float32"
+ y = 1.1 << (1.1 << s) // ERROR "invalid|truncated|float32"
var z complex128
- z = (1 << s) << (1 << s) // ERROR "type complex128"
- z = (1 << s) << (1. << s) // ERROR "type complex128"
- z = (1 << s) << (1.1 << s) // ERROR "invalid|1.1 truncated|complex128"
- z = (1. << s) << (1 << s) // ERROR "type complex128"
- z = (1. << s) << (1. << s) // ERROR "type complex128"
- z = (1.1 << s) << (1.1 << s) // ERROR "invalid|1.1 truncated|complex128"
+ z = (1 << s) << (1 << s) // ERROR "non-integer|type complex128"
+ z = (1 << s) << (1. << s) // ERROR "non-integer|type complex128"
+ z = (1 << s) << (1.1 << s) // ERROR "invalid|truncated|complex128"
+ z = (1. << s) << (1 << s) // ERROR "non-integer|type complex128"
+ z = (1. << s) << (1. << s) // ERROR "non-integer|type complex128"
+ z = (1.1 << s) << (1.1 << s) // ERROR "invalid|truncated|complex128"
}
コアとなるコードの解説
このコミットのコアとなる変更は、test/shift1.go
ファイル内の // ERROR
コメントの修正です。これらのコメントは、Goコンパイラが特定のコード行でエラーを報告することを期待するテストアサーションとして機能します。
変更のパターンは以下の通りです。
-
既存のエラーメッセージへの追加: 多くの行で、既存の期待されるエラーメッセージに
|
を使って新しいエラーメッセージのパターンが追加されています。これは、gc
とgccgo
の両方が生成する可能性のあるエラーメッセージをカバーするためです。- 例:
"invalid"
が"invalid|shift of non-integer operand"
に。 - 例:
"float64"
が"non-integer|float64"
に。 - 例:
"truncated"
が"non-integer|truncated"
に。
- 例:
-
より具体的なエラーメッセージの追加:
gccgo
がgc
よりも詳細なエラーメッセージを生成する場合があるため、それらのメッセージもテストで認識されるように追加されています。例えば、"non-integer" や "invalid" といったキーワードが追加されることで、より広範なエラーメッセージのバリエーションに対応しています。 -
complex
型やfloat
型のシフトに関するエラー: Go言語の仕様では、complex
型やfloat
型の値をシフトすることは許可されていません。このテストファイルはこれらのケースを網羅しており、今回の変更でgccgo
が出力する可能性のあるエラーメッセージ(例: "non-integer")も考慮されるようになりました。 -
make
やappend
の引数としてのシフト演算:make
やappend
の引数としてシフト演算の結果を使用する場合、その結果が期待される型(例えば、make
の長さは整数)に適合しない場合にエラーとなります。ここでも、gccgo
のエラーメッセージに対応するための調整が行われています。
これらの変更は、Go言語のテストスイートが、異なるコンパイラ実装(特に gc
と gccgo
)の間で、言語仕様の厳密な解釈とエラー報告の一貫性を維持していることを確認するための重要なステップです。これにより、Go言語の移植性と堅牢性が向上します。
関連リンク
- Go言語の仕様: https://go.dev/ref/spec (特に "Shift operators" のセクション)
- GCCGo プロジェクトページ: https://gcc.gnu.org/onlinedocs/gccgo/
参考にした情報源リンク
- Go言語の公式ドキュメント
- Go言語のソースコードリポジトリ (特に
go/src/cmd/compile/internal/typecheck/expr.go
やgo/src/cmd/compile/internal/gc/builtin.go
など、型チェックや組み込み関数の処理に関連するファイル) - GCCのドキュメント (GCCの内部構造やエラー報告メカニズムに関する一般的な情報)