[インデックス 17404] ファイルの概要
このコミットは、Goコンパイラ(cmd/gc
)において、組み込み型であるerror
、byte
、rune
のシンボル管理を修正し、それらが誤ってエクスポートされることを防ぐためのものです。これにより、これらの組み込み型がパッケージ外部から参照される際に発生する可能性のある問題を解決します。特に、Go言語の型システムとパッケージの可視性ルールに深く関連する変更です。
コミット
commit a85cfbd433646cba8227429854db59329414e223
Author: Rémy Oudompheng <oudomphe@phare.normalesup.org>
Date: Tue Aug 27 21:18:32 2013 +0200
cmd/gc: tag builtin error, byte, rune to avoid exporting them.
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a85cfbd433646cba8227429854db59329414e223
元コミット内容
cmd/gc: tag builtin error, byte, rune to avoid exporting them.
Fixes #5910.
Fixes #6260.
R=golang-dev, daniel.morsing
CC=golang-dev
https://golang.org/cl/13257044
変更の背景
このコミットは、Goコンパイラがerror
型、byte
エイリアス(uint8
のエイリアス)、rune
エイリアス(int32
のエイリアス)を処理する方法に関するバグを修正するために導入されました。具体的には、以下の2つのGoイシューを解決します。
-
Issue 5910: parsing of unnamed struct types in inlined bodies was broken. このイシューは、インライン化されたボディ内の無名構造体型のパースが壊れていたという問題です。直接的には
error
,byte
,rune
のエクスポートとは関係ないように見えますが、コンパイラのシンボル解決や型情報の取り扱いに関する根本的な問題が、これらの組み込み型の誤ったエクスポートと関連していた可能性があります。特に、型情報の不整合が、無名構造体のパースに影響を与えていた可能性が考えられます。 -
Issue 6260: このイシューについては、公開されている情報からは具体的な内容を特定できませんでした。しかし、コミットメッセージで言及されていることから、
error
,byte
,rune
のシンボル管理、またはそれらのエクスポートに関する別の問題であったと推測されます。
これらの問題の根底には、Goコンパイラが組み込み型をどのように内部的に表現し、シンボルテーブルに登録するかという点にありました。以前の実装では、これらの組み込み型が、あたかも通常のパッケージで定義されたエクスポート可能なシンボルであるかのように扱われる可能性があり、それが予期せぬ動作やコンパイルエラーを引き起こしていました。このコミットは、これらの組み込み型が常にbuiltinpkg
(組み込みパッケージ)に属するものとして正しくタグ付けされるようにすることで、この問題を解決します。
前提知識の解説
このコミットを理解するためには、Goコンパイラの内部構造、特に字句解析(lexical analysis)とシンボル管理に関する基本的な知識が必要です。
- Goコンパイラ (
cmd/gc
): Go言語の公式コンパイラの一つで、Goソースコードを機械語に変換します。gc
はGoコン言語で書かれており、その内部では字句解析、構文解析、型チェック、最適化、コード生成などのフェーズがあります。 - 字句解析 (Lexical Analysis): ソースコードをトークン(単語や記号の最小単位)のストリームに変換するプロセスです。このコミットが変更する
src/cmd/gc/lex.c
は、この字句解析フェーズの一部を担っています。 - シンボル (Symbol): プログラム内の識別子(変数名、関数名、型名など)を表す内部的なデータ構造です。コンパイラはシンボルテーブルを使って、これらの識別子に関する情報を管理します。
lookup(name)
: 字句解析中に識別子name
に対応するシンボルを検索または作成する関数です。これは現在のスコープ内でシンボルを見つけます。pkglookup(name, pkg)
: 特定のパッケージpkg
内で識別子name
に対応するシンボルを検索または作成する関数です。これは、パッケージの可視性ルールを考慮してシンボルを扱います。builtinpkg
: Go言語の組み込み型(int
,string
,bool
,error
,byte
,rune
など)が属する特別な内部パッケージです。これらの型は、どのGoプログラムでも特別なインポートなしに利用できます。lexical
フィールドとLNAME
: シンボル構造体内のフィールドで、そのシンボルの字句的な種類を示します。LNAME
は、そのシンボルが名前(識別子)であることを示します。sym
フィールド: 型情報(Type
構造体)が関連付けられているシンボルへのポインタです。def
フィールドとtypenod(type)
: シンボルが定義するノード(抽象構文木の一部)へのポインタです。typenod(type)
は、与えられた型に対応する型ノードを作成または取得する関数です。error
型: Go言語の組み込みインターフェース型で、エラーを表すために使用されます。byte
エイリアス:uint8
型のエイリアスです。rune
エイリアス:int32
型のエイリアスで、Unicodeコードポイントを表すために使用されます。- エクスポート (Exporting): Go言語では、識別子が大文字で始まる場合、その識別子はパッケージ外部からアクセス可能(エクスポートされる)になります。小文字で始まる識別子は、そのパッケージ内でのみアクセス可能です。組み込み型は、どのパッケージからもアクセス可能ですが、これは特別なメカニズムによるものであり、通常の「エクスポート」とは異なります。このコミットは、コンパイラがこれらの組み込み型を通常の「エクスポートされた」シンボルとして誤って扱わないようにするためのものです。
技術的詳細
このコミットの核心は、Goコンパイラのsrc/cmd/gc/lex.c
ファイル内のlexinit1
関数におけるerror
、byte
、rune
の初期化ロジックの変更です。
以前の実装では、これらの組み込み型に対応するシンボル(s
)をlookup("error")
のように現在のスコープで検索または作成した後、そのシンボルを直接型(errortype
, bytetype
, runetype
)のsym
フィールドに割り当てていました。
// 変更前 (例: error型)
s = lookup("error");
s->lexical = LNAME;
errortype = t;
errortype->sym = s; // ここで問題が発生
このs
は、現在のコンパイルユニットのシンボルテーブルに登録されるため、場合によっては、これらの組み込み型が通常のユーザー定義型と同様に扱われ、エクスポート可能であるかのように誤解釈される可能性がありました。Go言語の仕様では、error
, byte
, rune
は特別な組み込み型であり、特定のパッケージに属するエクスポートされた型として扱われるべきではありません。
このコミットでは、この問題を解決するために、pkglookup("error", builtinpkg)
を使用して、これらの組み込み型が明示的にbuiltinpkg
(組み込みパッケージ)に属するシンボルとして扱われるように変更しました。
// 変更後 (例: error型)
s = lookup("error"); // これは引き続き現在のスコープでシンボルを検索/作成
s->lexical = LNAME;
s1 = pkglookup("error", builtinpkg); // ここでbuiltinpkgに属するシンボルを取得
errortype = t;
errortype->sym = s1; // 型のsymフィールドにbuiltinpkgのシンボルを割り当てる
s1->lexical = LNAME;
s1->def = typenod(errortype);
変更のポイントは、errortype->sym = s;
を errortype->sym = s1;
に変更した点です。ここでs1
はpkglookup
によってbuiltinpkg
に紐付けられたシンボルです。これにより、error
、byte
、rune
の型情報が、常にbuiltinpkg
のコンテキストで正しく解決されるようになります。
この修正により、コンパイラはこれらの組み込み型を、通常のパッケージで定義されたエクスポート可能な型とは異なる、特別な組み込み型として正しく認識し、処理できるようになります。これにより、Issue 5910のような、型情報の不整合に起因するパースの問題や、組み込み型が誤ってエクスポートされることによる予期せぬ動作が防止されます。
テストケースの変更も重要です。test/fixedbugs/bug460.dir/b.go
では、Foo
構造体のフィールドとしてerror
, rune
, byte
が追加され、それらが「unexported field」(エクスポートされていないフィールド)としてアクセスされた場合にエラーとなることを確認しています。これは、これらの型が通常のフィールドとして扱われるべきであり、特別なエクスポートルールに縛られないことを示唆しています。また、test/fixedbugs/issue5910.dir/a.go
とmain.go
の変更は、error
型が構造体のフィールドや関数の戻り値として正しく扱われることを確認しており、特に無名構造体との組み合わせでのパースの問題が解決されたことを示しています。
コアとなるコードの変更箇所
このコミットで変更された主要なファイルとコードスニペットは以下の通りです。
src/cmd/gc/lex.c
lexinit1
関数内で、error
、byte
、rune
の各組み込み型の初期化ロジックが変更されています。
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -2008,27 +2008,27 @@ lexinit1(void)\n \t// error type\n \ts = lookup(\"error\");\n \ts->lexical = LNAME;\n-\terrortype = t;\n-\terrortype->sym = s;\n \ts1 = pkglookup(\"error\", builtinpkg);\n+\terrortype = t;\n+\terrortype->sym = s1;\n \ts1->lexical = LNAME;\n \ts1->def = typenod(errortype);\n \n \t// byte alias\n \ts = lookup(\"byte\");\n \ts->lexical = LNAME;\n-\tbytetype = typ(TUINT8);\n-\tbytetype->sym = s;\n \ts1 = pkglookup(\"byte\", builtinpkg);\n+\tbytetype = typ(TUINT8);\n+\tbytetype->sym = s1;\n \ts1->lexical = LNAME;\n \ts1->def = typenod(bytetype);\n \n \t// rune alias\n \ts = lookup(\"rune\");\n \ts->lexical = LNAME;\n-\trunetype = typ(TINT32);\n-\trunetype->sym = s;\n \ts1 = pkglookup(\"rune\", builtinpkg);\n+\trunetype = typ(TINT32);\n+\trunetype->sym = s1;\n \ts1->lexical = LNAME;\n \ts1->def = typenod(runetype);\n }\n```
### `test/fixedbugs/bug460.dir/a.go`
テスト用の構造体`Foo`に`error`, `rune`, `byte`フィールドが追加されています。
```diff
--- a/test/fixedbugs/bug460.dir/a.go
+++ b/test/fixedbugs/bug460.dir/a.go
@@ -6,4 +6,8 @@ package a
type Foo struct {\n \tint\n+\tint8\n+\terror\n+\trune\n+\tbyte\n }\n```
### `test/fixedbugs/bug460.dir/b.go`
`bug460.dir/a.go`で定義された`Foo`構造体の`error`, `rune`, `byte`フィールドへのアクセスが、`unexported field`エラーとして検出されることを確認するテストが追加されています。
```diff
--- a/test/fixedbugs/bug460.dir/b.go
+++ b/test/fixedbugs/bug460.dir/b.go
@@ -9,6 +9,9 @@ import \"./a\"\n var x a.Foo\n \n func main() {\n-\tx.int = 20 // ERROR \"unexported field\"\n+\tx.int = 20 // ERROR \"unexported field\"\n+\tx.int8 = 20 // ERROR \"unexported field\"\n+\tx.error = nil // ERROR \"unexported field\"\n+\tx.rune = \'a\' // ERROR \"unexported field\"\n+\tx.byte = 20 // ERROR \"unexported field\"\n }\n```
### `test/fixedbugs/issue5910.dir/a.go`
`Future`構造体の`result`チャネルの型に`error`が追加され、`Result()`メソッドが`error`も返すように変更されています。
```diff
--- a/test/fixedbugs/issue5910.dir/a.go
+++ b/test/fixedbugs/issue5910.dir/a.go
@@ -1,3 +1,7 @@
+// Copyright 2013 The Go Authors. All rights reserved.\n+// Use of this source code is governed by a BSD-style\n+// license that can be found in the LICENSE file.\n+\n package a
type Package struct {\n@@ -7,11 +11,12 @@ type Package struct {\n type Future struct {\n \tresult chan struct {\n \t\t*Package\n+\t\terror\n \t}\n }\n \n-func (t *Future) Result() *Package {\n+func (t *Future) Result() (*Package, error) {\n \tresult := <-t.result\n \tt.result <- result\n-\treturn result.Package\n+\treturn result.Package, result.error\n }\n```
### `test/fixedbugs/issue5910.dir/main.go`
`issue5910.dir/a.go`の変更に合わせて、`main.go`にも著作権表示が追加されています。
```diff
--- a/test/fixedbugs/issue5910.dir/main.go
+++ b/test/fixedbugs/issue5910.dir/main.go
@@ -1,3 +1,7 @@
+// Copyright 2013 The Go Authors. All rights reserved.\n+// Use of this source code is governed by a BSD-style\n+// license that can be found in the LICENSE file.\n+\n package main
import \"a\"\n```
## コアとなるコードの解説
`src/cmd/gc/lex.c`の変更は、Goコンパイラの字句解析器が組み込み型(`error`, `byte`, `rune`)をどのようにシンボルテーブルに登録し、型情報と関連付けるかを根本的に変更しています。
変更前は、`lookup("error")`のように、現在のスコープでシンボル`s`を取得し、その`s`を直接`errortype->sym`に割り当てていました。これは、これらの組み込み型が、あたかも通常のパッケージで定義された型であるかのように扱われる可能性をはらんでいました。Goの可視性ルールでは、大文字で始まる識別子はエクスポートされますが、`error`, `byte`, `rune`は特別な組み込み型であり、通常のパッケージのエクスポートルールには従いません。しかし、コンパイラの内部処理で誤って通常のシンボルとして扱われると、予期せぬ問題が発生する可能性がありました。
変更後は、`pkglookup("error", builtinpkg)`という新しい呼び出しが導入され、その結果得られるシンボル`s1`が`errortype->sym`に割り当てられています。
* `s = lookup("error");` は引き続き存在し、これは現在のスコープで`"error"`という名前のシンボルを検索または作成します。これは、例えば`error`という名前のローカル変数や型が定義された場合に、それらを正しく解決するために必要です。
* `s1 = pkglookup("error", builtinpkg);` が重要な変更点です。`pkglookup`は、指定されたパッケージ(ここでは`builtinpkg`)内でシンボルを検索または作成します。これにより、`error`型が常に`builtinpkg`に属するシンボルとして明示的にタグ付けされます。
* `errortype->sym = s1;` とすることで、`error`型の内部表現が、`builtinpkg`に紐付けられたシンボルを指すようになります。これにより、コンパイラは`error`型を、通常のパッケージの可視性ルールに縛られない、特別な組み込み型として正しく認識し、処理できるようになります。
同様の変更が`byte`と`rune`にも適用されています。これにより、これらの組み込み型がGoコンパイラによって一貫して正しく扱われるようになり、Issue 5910のような型情報の不整合に起因するバグが修正されました。
テストケースの変更は、この修正が意図した通りに機能することを確認しています。
* `bug460.dir`のテストは、`error`, `byte`, `rune`が構造体のフィールドとして使用された場合に、通常のフィールドと同様にエクスポートルールが適用されることを確認しています。これは、これらの型が特別な組み込み型として扱われる一方で、通常の型としての振る舞いも維持していることを示しています。
* `issue5910.dir`のテストは、`error`型が無名構造体のフィールドとして使用された場合に、コンパイラが正しくパースできることを確認しています。これは、このコミットが解決しようとした主要な問題の一つである、無名構造体と組み込み型の組み合わせにおけるパースのバグが修正されたことを示しています。
## 関連リンク
* Go Issue 5910: [https://go.dev/issue/5910](https://go.dev/issue/5910)
* Go Issue 6260: (公開されている情報からは具体的な内容を特定できませんでした)
* Go CL 13257044: [https://golang.org/cl/13257044](https://golang.org/cl/13257044)
## 参考にした情報源リンク
* Go Issue 5910の検索結果: [https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEKkr6IKa7Tbhhtpjny6cLR00JKGXAnqIW6s-uZwROtVdo_oYrNbd-Z-lEvqosoRAGuH8tUK54HCbHmr5xamUrTom6t87jDNn7mu1CDqruYmoV-Sx82V7Sd_aEShabJFFLZ7U_pNw==](https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEKkr6IKa7Tbhhtpjny6cLR00JKGXAnqIW6s-uZwROtVdo_oYrNbd-Z-lEvqosoRAGuH8tUK54HCbHmr5xamUrTom6t87jDNn7mu1CDqruYmoV-Sx82V7Sd_aEShabJFFLZ7U_pNw==)
* Go言語のソースコード (特に`src/cmd/gc/lex.c`): [https://github.com/golang/go/blob/master/src/cmd/gc/lex.c](https://github.com/golang/go/blob/master/src/cmd/gc/lex.c) (コミット時点のバージョンとは異なる可能性があります)
* Go言語の仕様 (型、パッケージ、可視性ルールなど): [https://go.dev/ref/spec](https://go.dev/ref/spec)# [インデックス 17404] ファイルの概要
このコミットは、Goコンパイラ(`cmd/gc`)において、組み込み型である`error`、`byte`、`rune`のシンボル管理を修正し、それらが誤ってエクスポートされることを防ぐためのものです。これにより、これらの組み込み型がパッケージ外部から参照される際に発生する可能性のある問題を解決します。特に、Go言語の型システムとパッケージの可視性ルールに深く関連する変更です。
## コミット
commit a85cfbd433646cba8227429854db59329414e223 Author: Rémy Oudompheng oudomphe@phare.normalesup.org Date: Tue Aug 27 21:18:32 2013 +0200
cmd/gc: tag builtin error, byte, rune to avoid exporting them.
## GitHub上でのコミットページへのリンク
[https://github.com/golang/go/commit/a85cfbd433646cba8227429854db59329414e223](https://github.com/golang/go/commit/a85cfbd433646cba8227429854db59329414e223)
## 元コミット内容
cmd/gc: tag builtin error, byte, rune to avoid exporting them.
Fixes #5910. Fixes #6260.
R=golang-dev, daniel.morsing CC=golang-dev https://golang.org/cl/13257044
## 変更の背景
このコミットは、Goコンパイラが`error`型、`byte`エイリアス(`uint8`のエイリアス)、`rune`エイリアス(`int32`のエイリアス)を処理する方法に関するバグを修正するために導入されました。具体的には、以下の2つのGoイシューを解決します。
* **Issue 5910: parsing of unnamed struct types in inlined bodies was broken.**
このイシューは、インライン化されたボディ内の無名構造体型のパースが壊れていたという問題です。直接的には`error`, `byte`, `rune`のエクスポートとは関係ないように見えますが、コンパイラのシンボル解決や型情報の取り扱いに関する根本的な問題が、これらの組み込み型の誤ったエクスポートと関連していた可能性があります。特に、型情報の不整合が、無名構造体のパースに影響を与えていた可能性が考えられます。
* **Issue 6260:**
このイシューについては、公開されている情報からは具体的な内容を特定できませんでした。しかし、コミットメッセージで言及されていることから、`error`, `byte`, `rune`のシンボル管理、またはそれらのエクスポートに関する別の問題であったと推測されます。
これらの問題の根底には、Goコンパイラが組み込み型をどのように内部的に表現し、シンボルテーブルに登録するかという点にありました。以前の実装では、これらの組み込み型が、あたかも通常のパッケージで定義されたエクスポート可能なシンボルであるかのように扱われる可能性があり、それが予期せぬ動作やコンパイルエラーを引き起こしていました。このコミットは、これらの組み込み型が常に`builtinpkg`(組み込みパッケージ)に属するものとして正しくタグ付けされるようにすることで、この問題を解決します。
## 前提知識の解説
このコミットを理解するためには、Goコンパイラの内部構造、特に字句解析(lexical analysis)とシンボル管理に関する基本的な知識が必要です。
* **Goコンパイラ (`cmd/gc`)**: Go言語の公式コンパイラの一つで、Goソースコードを機械語に変換します。`gc`はGoコン言語で書かれており、その内部では字句解析、構文解析、型チェック、最適化、コード生成などのフェーズがあります。
* **字句解析 (Lexical Analysis)**: ソースコードをトークン(単語や記号の最小単位)のストリームに変換するプロセスです。このコミットが変更する`src/cmd/gc/lex.c`は、この字句解析フェーズの一部を担っています。
* **シンボル (Symbol)**: プログラム内の識別子(変数名、関数名、型名など)を表す内部的なデータ構造です。コンパイラはシンボルテーブルを使って、これらの識別子に関する情報を管理します。
* **`lookup(name)`**: 字句解析中に識別子`name`に対応するシンボルを検索または作成する関数です。これは現在のスコープ内でシンボルを見つけます。
* **`pkglookup(name, pkg)`**: 特定のパッケージ`pkg`内で識別子`name`に対応するシンボルを検索または作成する関数です。これは、パッケージの可視性ルールを考慮してシンボルを扱います。
* **`builtinpkg`**: Go言語の組み込み型(`int`, `string`, `bool`, `error`, `byte`, `rune`など)が属する特別な内部パッケージです。これらの型は、どのGoプログラムでも特別なインポートなしに利用できます。
* **`lexical` フィールドと `LNAME`**: シンボル構造体内のフィールドで、そのシンボルの字句的な種類を示します。`LNAME`は、そのシンボルが名前(識別子)であることを示します。
* **`sym` フィールド**: 型情報(`Type`構造体)が関連付けられているシンボルへのポインタです。
* **`def` フィールドと `typenod(type)`**: シンボルが定義するノード(抽象構文木の一部)へのポインタです。`typenod(type)`は、与えられた型に対応する型ノードを作成または取得する関数です。
* **`error` 型**: Go言語の組み込みインターフェース型で、エラーを表すために使用されます。
* **`byte` エイリアス**: `uint8`型のエイリアスです。
* **`rune` エイリアス**: `int32`型のエイリアスで、Unicodeコードポイントを表すために使用されます。
* **エクスポート (Exporting)**: Go言語では、識別子が大文字で始まる場合、その識別子はパッケージ外部からアクセス可能(エクスポートされる)になります。小文字で始まる識別子は、そのパッケージ内でのみアクセス可能です。組み込み型は、どのパッケージからもアクセス可能ですが、これは特別なメカニズムによるものであり、通常の「エクスポート」とは異なります。このコミットは、コンパイラがこれらの組み込み型を通常の「エクスポートされた」シンボルとして誤って扱わないようにするためのものです。
## 技術的詳細
このコミットの核心は、Goコンパイラの`src/cmd/gc/lex.c`ファイル内の`lexinit1`関数における`error`、`byte`、`rune`の初期化ロジックの変更です。
以前の実装では、これらの組み込み型に対応するシンボル(`s`)を`lookup("error")`のように現在のスコープで検索または作成した後、そのシンボルを直接型(`errortype`, `bytetype`, `runetype`)の`sym`フィールドに割り当てていました。
```c
// 変更前 (例: error型)
s = lookup("error");
s->lexical = LNAME;
errortype = t;
errortype->sym = s; // ここで問題が発生
このs
は、現在のコンパイルユニットのシンボルテーブルに登録されるため、場合によっては、これらの組み込み型が通常のユーザー定義型と同様に扱われ、エクスポート可能であるかのように誤解釈される可能性がありました。Go言語の仕様では、error
, byte
, rune
は特別な組み込み型であり、特定のパッケージに属するエクスポートされた型として扱われるべきではありません。
このコミットでは、この問題を解決するために、pkglookup("error", builtinpkg)
を使用して、これらの組み込み型が明示的にbuiltinpkg
(組み込みパッケージ)に属するシンボルとして扱われるように変更しました。
// 変更後 (例: error型)
s = lookup("error"); // これは引き続き現在のスコープでシンボルを検索/作成
s->lexical = LNAME;
s1 = pkglookup("error", builtinpkg); // ここでbuiltinpkgに属するシンボルを取得
errortype = t;
errortype->sym = s1; // 型のsymフィールドにbuiltinpkgのシンボルを割り当てる
s1->lexical = LNAME;
s1->def = typenod(errortype);
変更のポイントは、errortype->sym = s;
を errortype->sym = s1;
に変更した点です。ここでs1
はpkglookup
によってbuiltinpkg
に紐付けられたシンボルです。これにより、error
型の内部表現が、常にbuiltinpkg
のコンテキストで正しく解決されるようになります。
この修正により、コンパイラはこれらの組み込み型を、通常のパッケージで定義されたエクスポート可能な型とは異なる、特別な組み込み型として正しく認識し、処理できるようになります。これにより、Issue 5910のような、型情報の不整合に起因するパースの問題や、組み込み型が誤ってエクスポートされることによる予期せぬ動作が防止されます。
テストケースの変更も重要です。test/fixedbugs/bug460.dir/b.go
では、Foo
構造体のフィールドとしてerror
, rune
, byte
が追加され、それらが「unexported field」(エクスポートされていないフィールド)としてアクセスされた場合にエラーとなることを確認しています。これは、これらの型が通常のフィールドとして扱われるべきであり、特別なエクスポートルールに縛られないことを示唆しています。また、test/fixedbugs/issue5910.dir/a.go
とmain.go
の変更は、error
型が構造体のフィールドや関数の戻り値として正しく扱われることを確認しており、特に無名構造体との組み合わせでのパースの問題が解決されたことを示しています。
コアとなるコードの変更箇所
このコミットで変更された主要なファイルとコードスニペットは以下の通りです。
src/cmd/gc/lex.c
lexinit1
関数内で、error
、byte
、rune
の各組み込み型の初期化ロジックが変更されています。
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -2008,27 +2008,27 @@ lexinit1(void)\n \t// error type\n \ts = lookup(\"error\");\n \ts->lexical = LNAME;\n-\terrortype = t;\n-\terrortype->sym = s;\n \ts1 = pkglookup(\"error\", builtinpkg);\n+\terrortype = t;\n+\terrortype->sym = s1;\n \ts1->lexical = LNAME;\n \ts1->def = typenod(errortype);\n \n \t// byte alias\n \ts = lookup(\"byte\");\n \ts->lexical = LNAME;\n-\tbytetype = typ(TUINT8);\n-\tbytetype->sym = s;\n \ts1 = pkglookup(\"byte\", builtinpkg);\n+\tbytetype = typ(TUINT8);\n+\tbytetype->sym = s1;\n \ts1->lexical = LNAME;\n \ts1->def = typenod(bytetype);\n \n \t// rune alias\n \ts = lookup(\"rune\");\n \ts->lexical = LNAME;\n-\trunetype = typ(TINT32);\n-\trunetype->sym = s;\n \ts1 = pkglookup(\"rune\", builtinpkg);\n+\trunetype = typ(TINT32);\n+\trunetype->sym = s1;\n \ts1->lexical = LNAME;\n \ts1->def = typenod(runetype);\n }\n```
### `test/fixedbugs/bug460.dir/a.go`
テスト用の構造体`Foo`に`error`, `rune`, `byte`フィールドが追加されています。
```diff
--- a/test/fixedbugs/bug460.dir/a.go
+++ b/test/fixedbugs/bug460.dir/a.go
@@ -6,4 +6,8 @@ package a
type Foo struct {\n \tint\n+\tint8\n+\terror\n+\trune\n+\tbyte\n }\n```
### `test/fixedbugs/bug460.dir/b.go`
`bug460.dir/a.go`で定義された`Foo`構造体の`error`, `rune`, `byte`フィールドへのアクセスが、`unexported field`エラーとして検出されることを確認するテストが追加されています。
```diff
--- a/test/fixedbugs/bug460.dir/b.go
+++ b/test/fixedbugs/bug460.dir/b.go
@@ -9,6 +9,9 @@ import \"./a\"\n var x a.Foo\n \n func main() {\n-\tx.int = 20 // ERROR \"unexported field\"\n+\tx.int = 20 // ERROR \"unexported field\"\n+\tx.int8 = 20 // ERROR \"unexported field\"\n+\tx.error = nil // ERROR \"unexported field\"\n+\tx.rune = \'a\' // ERROR \"unexported field\"\n+\tx.byte = 20 // ERROR \"unexported field\"\n }\n```
### `test/fixedbugs/issue5910.dir/a.go`
`Future`構造体の`result`チャネルの型に`error`が追加され、`Result()`メソッドが`error`も返すように変更されています。
```diff
--- a/test/fixedbugs/issue5910.dir/a.go
+++ b/test/fixedbugs/issue5910.dir/a.go
@@ -1,3 +1,7 @@
+// Copyright 2013 The Go Authors. All rights reserved.\n+// Use of this source code is governed by a BSD-style\n+// license that can be found in the LICENSE file.\n+\n package a
type Package struct {\n@@ -7,11 +11,12 @@ type Package struct {\n type Future struct {\n \tresult chan struct {\n \t\t*Package\n+\t\terror\n \t}\n }\n \n-func (t *Future) Result() *Package {\n+func (t *Future) Result() (*Package, error) {\n \tresult := <-t.result\n \tt.result <- result\n-\treturn result.Package\n+\treturn result.Package, result.error\n }\n```
### `test/fixedbugs/issue5910.dir/main.go`
`issue5910.dir/a.go`の変更に合わせて、`main.go`にも著作権表示が追加されています。
```diff
--- a/test/fixedbugs/issue5910.dir/main.go
+++ b/test/fixedbugs/issue5910.dir/main.go
@@ -1,3 +1,7 @@
+// Copyright 2013 The Go Authors. All rights reserved.\n+// Use of this source code is governed by a BSD-style\n+// license that can be found in the LICENSE file.\n+\n package main
import \"a\"\n```
## コアとなるコードの解説
`src/cmd/gc/lex.c`の変更は、Goコンパイラの字句解析器が組み込み型(`error`, `byte`, `rune`)をどのようにシンボルテーブルに登録し、型情報と関連付けるかを根本的に変更しています。
変更前は、`lookup("error")`のように、現在のスコープでシンボル`s`を取得し、その`s`を直接`errortype->sym`に割り当てていました。これは、これらの組み込み型が、あたかも通常のパッケージで定義された型であるかのように扱われる可能性をはらんでいました。Goの可視性ルールでは、大文字で始まる識別子はエクスポートされますが、`error`, `byte`, `rune`は特別な組み込み型であり、通常のパッケージのエクスポートルールには従いません。しかし、コンパイラの内部処理で誤って通常のシンボルとして扱われると、予期せぬ問題が発生する可能性がありました。
変更後は、`pkglookup("error", builtinpkg)`という新しい呼び出しが導入され、その結果得られるシンボル`s1`が`errortype->sym`に割り当てられています。
* `s = lookup("error");` は引き続き存在し、これは現在のスコープで`"error"`という名前のシンボルを検索または作成します。これは、例えば`error`という名前のローカル変数や型が定義された場合に、それらを正しく解決するために必要です。
* `s1 = pkglookup("error", builtinpkg);` が重要な変更点です。`pkglookup`は、指定されたパッケージ(ここでは`builtinpkg`)内でシンボルを検索または作成します。これにより、`error`型が常に`builtinpkg`に属するシンボルとして明示的にタグ付けされます。
* `errortype->sym = s1;` とすることで、`error`型の内部表現が、`builtinpkg`に紐付けられたシンボルを指すようになります。これにより、コンパイラは`error`型を、通常のパッケージの可視性ルールに縛られない、特別な組み込み型として正しく認識し、処理できるようになります。
同様の変更が`byte`と`rune`にも適用されています。これにより、これらの組み込み型がGoコンパイラによって一貫して正しく扱われるようになり、Issue 5910のような型情報の不整合に起因するバグが修正されました。
テストケースの変更は、この修正が意図した通りに機能することを確認しています。
* `bug460.dir`のテストは、`error`, `byte`, `rune`が構造体のフィールドとして使用された場合に、通常のフィールドと同様にエクスポートルールが適用されることを確認しています。これは、これらの型が特別な組み込み型として扱われる一方で、通常の型としての振る舞いも維持していることを示しています。
* `issue5910.dir`のテストは、`error`型が無名構造体のフィールドとして使用された場合に、コンパイラが正しくパースできることを確認しています。これは、このコミットが解決しようとした主要な問題の一つである、無名構造体と組み込み型の組み合わせにおけるパースのバグが修正されたことを示しています。
## 関連リンク
* Go Issue 5910: [https://go.dev/issue/5910](https://go.dev/issue/5910)
* Go Issue 6260: (公開されている情報からは具体的な内容を特定できませんでした)
* Go CL 13257044: [https://golang.org/cl/13257044](https://golang.org/cl/13257044)
## 参考にした情報源リンク
* Go Issue 5910の検索結果: [https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEKkr6IKa7Tbhhtpjny6cLR00JKGXAnqIW6s-uZwROtVdo_oYrNbd-Z-lEvqosoRAGuH8tUK54HCbHmr5xamUrTom6t87jDNn7mu1CDqruYmoV-Sx82V7Sd_aEShabJFFLZ7U_pNw==](https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEKkr6IKa7Tbhhtpjny6cLR00JKGXAnqIW6s-uZwROtVdo_oYrNbd-Z-lEvqosoRAGuH8tUK54HCbHmr5xamUrTom6t87jDNn7mu1CDqruYmoV-Sx82V7Sd_aEShabJFFLZ7U_pNw==)
* Go言語のソースコード (特に`src/cmd/gc/lex.c`): [https://github.com/golang/go/blob/master/src/cmd/gc/lex.c](https://github.com/golang/go/blob/master/src/cmd/gc/lex.c) (コミット時点のバージョンとは異なる可能性があります)
* Go言語の仕様 (型、パッケージ、可視性ルールなど): [https://go.dev/ref/spec](https://go.dev/ref/spec)