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

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

このコミットは、Goコンパイラ(cmd/gc)内のordermapassign関数におけるタイプミスを修正するものです。具体的には、マップ要素への代入処理において、誤ったノードがコピーされるバグを修正しています。この修正により、Go言語のマップ代入に関するコンパイル時の問題が解決されました。

コミット

  • コミットハッシュ: f973d9460f1e65e5d53f2d0681256b89bcedbfd3
  • Author: Jan Ziak 0xe2.0x9a.0x9b@gmail.com
  • Date: Fri Apr 11 15:28:37 2014 +0200
  • コミットメッセージ:
    cmd/gc: fix typo in ordermapassign
    
    Fixes #7742
    
    LGTM=dave, rsc
    R=rsc, bradfitz, dave
    CC=golang-codereviews
    https://golang.org/cl/85580047
    

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

https://github.com/golang/go/commit/f973d9460f1e65e5d53f2d0681256b89bcedbfd3

元コミット内容

cmd/gc: fix typo in ordermapassign

Fixes #7742

LGTM=dave, rsc
R=rsc, bradfitz, dave
CC=golang-codereviews
https://golang.org/cl/85580047

変更の背景

このコミットは、Goコンパイラ(cmd/gc)のordermapassign関数に存在するタイプミスによって引き起こされるバグを修正するために行われました。コミットメッセージにあるFixes #7742が示す通り、GoのIssueトラッカーで報告されたバグ(Issue 7742)に対応するものです。

Issue 7742は、マップ要素への代入(例: m[key] = value)において、コンパイラが内部的に誤った抽象構文木(AST)ノードを処理してしまう問題でした。具体的には、代入の右辺(value)を処理すべき箇所で、誤って左辺(key)のノードを再利用してしまうというタイプミスが原因でした。この誤りにより、特定の状況下でコンパイルエラーや不正なコード生成が発生する可能性がありました。

このバグは、特にマップのキーと値が同じ変数であるような代入(例: m[v], _ = v, v)で顕在化し、コンパイラが型チェックの段階で混乱し、cannot use &autotmp_0001 (type *map[string]string) as type *string in function argumentのようなエラーメッセージを出すことがありました。これは、コンパイラが一時変数(autotmp_0001)の型を誤って解釈した結果です。

前提知識の解説

Goコンパイラ (cmd/gc)

Go言語の公式コンパイラは、gc(Go Compiler)と呼ばれ、Goのソースコードを機械語に変換する役割を担っています。cmd/gcは、そのコンパイラのフロントエンド部分であり、字句解析、構文解析、抽象構文木(AST)の構築、型チェック、最適化、コード生成など、コンパイルの主要なフェーズを実行します。

抽象構文木 (AST) と Node

コンパイラは、ソースコードを直接処理するのではなく、まずその構造を抽象化したデータ構造である抽象構文木(AST)に変換します。ASTは、プログラムの構造を木構造で表現したもので、各ノードは変数、式、文などのプログラム要素に対応します。Goコンパイラでは、これらのASTノードがNode構造体として表現されます。

ordermapassign 関数

ordermapassignは、Goコンパイラのcmd/gcパッケージ内のorder.cファイルに定義されている関数です。この関数は、マップ要素への代入(例: m[key] = value)を処理する際に呼び出されます。Go言語のマップは、内部的にハッシュテーブルとして実装されており、その要素へのアクセスや代入は、通常の変数への代入とは異なる複雑な処理を伴います。ordermapassignは、このようなマップ代入のセマンティクスを正しくコンパイルするための、ASTの変換や一時変数の導入、関数呼び出しの生成などを行います。

ordercopyexpr 関数

ordercopyexprは、Goコンパイラ内で使用されるユーティリティ関数で、特定の式(Node)をコピーし、必要に応じてその評価順序を調整する役割を持ちます。コンパイラは、最適化やコード生成の過程で、同じ式が複数回評価されることを避けるため、あるいは特定の評価順序を強制するために、式のコピーや一時変数への格納を行うことがあります。ordercopyexprは、このような文脈で利用されます。

istemp 関数

istempは、与えられたNodeがコンパイラによって生成された一時変数(temporary variable)であるかどうかを判定する関数です。コンパイラは、複雑な式や関数呼び出しの結果を一時的に保持するために、内部的に一時変数を導入することがよくあります。

OAS (Opcode for Assignment)

GoコンパイラのASTノードには、そのノードが表す操作の種類を示す「オペコード」が割り当てられています。OASは、代入操作(Assignment)を表すオペコードです。例えば、a = bという代入文は、OASオペコードを持つノードとしてASTに表現されます。

typecheck 関数

typecheckは、Goコンパイラの型チェックフェーズで呼び出される関数です。この関数は、ASTノードの型がGo言語の型システム規則に適合しているかを確認します。型チェックは、プログラムの正しさを保証し、実行時エラーを防ぐ上で非常に重要なステップです。

Go言語におけるマップの挙動

Go言語のマップは、キーと値のペアを格納する動的なデータ構造です。マップ要素への代入は、map[key] = valueという形式で行われます。この操作は、内部的にはキーのハッシュ値を計算し、そのハッシュ値に基づいてマップ内の適切なバケットに値を格納する、という複雑なプロセスを含みます。コンパイラは、この一連の操作を正しく機械語に変換する必要があります。

Issue 7742

GoのIssue 7742は、cmd/gc: cannot use &autotmp_0001 (type *map[string]string) as type *string in function argumentというエラーメッセージで報告されたバグです。このエラーは、マップのキーと値に同じ変数を代入しようとした際に発生しました。具体的には、m[v], _ = v, vのようなコードで、コンパイラがマップのキーと値の評価順序を誤り、型が一致しない一時変数を使用しようとしたために発生しました。

技術的詳細

このコミットの技術的詳細は、src/cmd/gc/order.cファイル内のordermapassign関数における単一のタイプミスに集約されます。

ordermapassign関数は、マップ要素への代入を処理する際に、代入の右辺(値)と左辺(キー)の式を適切に評価し、必要に応じて一時変数にコピーする役割を担っています。

問題のコードは以下の部分でした(修正前):

if(!istemp(m->right))
    m->right = ordercopyexpr(m->left, m->left->type, order, 0); // ここが問題

ここで、mはマップ代入を表すASTノードであり、m->leftはマップのキーを表すノード、m->rightはマップに代入される値を表すノードです。

本来、m->right(代入される値)が一時変数でない場合に、その値の式をコピーして一時変数に格納する処理を行うべきでした。しかし、タイプミスにより、ordercopyexprの第一引数にm->left(マップのキー)が渡されていました。つまり、代入される値の式をコピーする代わりに、誤ってマップのキーの式をコピーしてしまっていたのです。

この誤りにより、コンパイラはマップ代入の右辺の値を正しく処理できず、特にマップのキーと値が同じ変数であるようなケース(例: m[v], _ = v, v)で、型不一致のエラーや不正なコード生成を引き起こす可能性がありました。コンパイラは、マップのキーと値の評価順序を考慮し、それぞれを独立した一時変数として扱う必要がありますが、このタイプミスにより、値の評価が正しく行われず、結果として型システムが混乱しました。

修正は、このm->leftm->rightに置き換えるという非常に単純なものでしたが、Goコンパイラの内部処理における正確性の重要性を示しています。

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

--- a/src/cmd/gc/order.c
+++ b/src/cmd/gc/order.c
@@ -472,7 +472,7 @@ ordermapassign(Node *n, Order *order)
 			if(!istemp(m->left))
 				m->left = ordercopyexpr(m->left, m->left->type, order, 0);
 			if(!istemp(m->right))
-				m->right = ordercopyexpr(m->left, m->left->type, order, 0);
+				m->right = ordercopyexpr(m->right, m->right->type, order, 0);
 			l->n = ordertemp(m->type, order, 0);
 			a = nod(OAS, m, l->n);
 			typecheck(&a, Etop);
--- a/test/fixedbugs/issue7742.go
+++ b/test/fixedbugs/issue7742.go
@@ -0,0 +1,18 @@
+// compile
+
+// Copyright 2014 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 7742: cannot use &autotmp_0001 (type *map[string]string) as type *string in function argument
+
+package main
+
+var (
+	m map[string]string
+	v string
+)
+
+func main() {
+	m[v], _ = v, v
+}

コアとなるコードの解説

変更は主にsrc/cmd/gc/order.cファイル内のordermapassign関数にあります。

修正前のコード:

m->right = ordercopyexpr(m->left, m->left->type, order, 0);

この行では、マップ代入の右辺(m->right)を処理する際に、誤って左辺(m->left、つまりマップのキー)の式をordercopyexpr関数に渡していました。これにより、コンパイラはマップに代入されるべき値の式ではなく、キーの式をコピーしてしまい、結果として型不一致や不正なコード生成の原因となっていました。

修正後のコード:

m->right = ordercopyexpr(m->right, m->right->type, order, 0);

この修正では、ordercopyexprに渡す第一引数をm->leftからm->rightに、第二引数もm->left->typeからm->right->typeに修正しています。これにより、ordermapassign関数は、マップ代入の右辺の式を正しくコピーし、必要に応じて一時変数に格納するようになりました。これは、マップのキーと値がそれぞれ独立して評価され、適切な型で処理されることを保証するために不可欠な変更です。

また、このコミットにはtest/fixedbugs/issue7742.goという新しいテストファイルが追加されています。このテストファイルは、m[v], _ = v, vという形式のマップ代入を含んでおり、修正前のコンパイラではこのコードがエラーになることを再現し、修正後には正しくコンパイルされることを確認するためのものです。これは、バグが修正されたことを検証するための重要な回帰テストとなります。

関連リンク

参考にした情報源リンク

  • Go Issue Tracker: https://github.com/golang/go/issues
  • Go Source Code: https://github.com/golang/go
  • Go Compiler Internals (非公式資料など): Goコンパイラの内部構造に関する一般的な知識。
  • Go言語のマップに関する公式ドキュメントやブログ記事。
  • C言語のポインタと構造体に関する一般的な知識。
  • コンパイラの基本的な概念(AST、型チェック、コード生成など)。 I have generated the detailed explanation in Markdown format, following all the specified instructions and chapter structure. The output is to standard output only. I have included the background, prerequisite knowledge, and technical details as requested. I also used the provided GitHub URL and found the corresponding Go Issue 7742 to provide more context.

The response is now complete.