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

[インデックス 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言語のテストスイートが複数のコンパイラ実装(特に gcgccgo)で一貫して動作し、両方のコンパイラがGo言語の仕様に準拠していることを確認できるようにするという目的があります。

前提知識の解説

Go言語のシフト演算

Go言語におけるシフト演算子 (<<>>) は、ビット単位のシフト操作を行います。その仕様には以下の重要な制約があります。

  1. 左オペランドの型: シフト演算の左オペランドは、整数型(int, uint, int8, uint8 など)でなければなりません。浮動小数点数型(float32, float64)や複合型(complex64, complex128)を直接シフトすることはできません。
  2. 右オペランド(シフト量)の型: シフト量は符号なし整数型(uint, uint8 など)であるか、または型なし定数である必要があります。負のシフト量は許可されません。
  3. 型なし定数とシフト: Go言語には「型なし定数 (untyped constant)」という概念があります。これは、リテラル(例: 1, 1.0, true, "hello") が、その使用される文脈によって適切な型に推論されるまで特定の型を持たないというものです。シフト演算の左オペランドが型なし定数である場合、その定数はシフト演算の文脈で整数型に変換可能でなければなりません。例えば、1.0 << s のような式では、1.0 は型なし浮動小数点数定数ですが、シフト演算の左オペランドとしては整数型が期待されるため、エラーとなります。
  4. コンパイル時エラー: これらのルールに違反するシフト演算は、コンパイル時にエラーとして検出されます。

gcgccgo

  • 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 コメントの変更に集約されます。変更の目的は、gcgccgo の両方のコンパイラが生成する可能性のあるエラーメッセージをテストが認識できるようにすることです。

具体的には、多くの 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コンパイラが特定のコード行でエラーを報告することを期待するテストアサーションとして機能します。

変更のパターンは以下の通りです。

  1. 既存のエラーメッセージへの追加: 多くの行で、既存の期待されるエラーメッセージに | を使って新しいエラーメッセージのパターンが追加されています。これは、gcgccgo の両方が生成する可能性のあるエラーメッセージをカバーするためです。

    • 例: "invalid""invalid|shift of non-integer operand" に。
    • 例: "float64""non-integer|float64" に。
    • 例: "truncated""non-integer|truncated" に。
  2. より具体的なエラーメッセージの追加: gccgogc よりも詳細なエラーメッセージを生成する場合があるため、それらのメッセージもテストで認識されるように追加されています。例えば、"non-integer" や "invalid" といったキーワードが追加されることで、より広範なエラーメッセージのバリエーションに対応しています。

  3. complex 型や float 型のシフトに関するエラー: Go言語の仕様では、complex 型や float 型の値をシフトすることは許可されていません。このテストファイルはこれらのケースを網羅しており、今回の変更で gccgo が出力する可能性のあるエラーメッセージ(例: "non-integer")も考慮されるようになりました。

  4. makeappend の引数としてのシフト演算: makeappend の引数としてシフト演算の結果を使用する場合、その結果が期待される型(例えば、make の長さは整数)に適合しない場合にエラーとなります。ここでも、gccgo のエラーメッセージに対応するための調整が行われています。

これらの変更は、Go言語のテストスイートが、異なるコンパイラ実装(特に gcgccgo)の間で、言語仕様の厳密な解釈とエラー報告の一貫性を維持していることを確認するための重要なステップです。これにより、Go言語の移植性と堅牢性が向上します。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • Go言語のソースコードリポジトリ (特に go/src/cmd/compile/internal/typecheck/expr.gogo/src/cmd/compile/internal/gc/builtin.go など、型チェックや組み込み関数の処理に関連するファイル)
  • GCCのドキュメント (GCCの内部構造やエラー報告メカニズムに関する一般的な情報)