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

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

このコミットは、Goコンパイラのcmd/gcにおける「not used」メッセージの表示行に関するバグを修正するものです。具体的には、Go言語のパーサーが生成する抽象構文木(AST)のノードに、正しい行番号情報が付与されるように変更が加えられています。これにより、コンパイラが未使用の変数などを検出した際に、より正確なエラーメッセージをユーザーに提示できるようになります。

コミット

commit e2711cb202081261d4586be525b6281544a7dac7
Author: Russ Cox <rsc@golang.org>
Date:   Fri Feb 1 21:13:41 2013 -0500

    cmd/gc: put 'not used' message on correct line
    
    Fixes #4663.
    
    R=ken2
    CC=golang-dev
    https://golang.org/cl/7235081

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

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

元コミット内容

cmd/gc: put 'not used' message on correct line

このコミットは、Goコンパイラのcmd/gc部分において、「not used」(未使用)というメッセージが誤った行番号で表示される問題を修正します。これは、Go言語のIssue #4663に対応するものです。

変更の背景

Goコンパイラは、ソースコードを解析して抽象構文木(AST)を構築し、そのASTを基に様々なチェックや最適化を行います。この過程で、例えば宣言されたが使用されていない変数など、特定のコード要素に対して警告やエラーメッセージを生成することがあります。

Issue #4663では、これらの「not used」メッセージが、実際に問題のあるコードの行ではなく、異なる行番号で報告されるという問題が指摘されていました。これは、コンパイラのフロントエンド、特に字句解析(lexing)と構文解析(parsing)の段階で、ASTノードに付与される行番号情報が不正確であったことに起因すると考えられます。

正確なエラーメッセージは、開発者が問題を迅速に特定し、修正するために不可欠です。そのため、このコミットは、コンパイラの診断機能の精度を向上させることを目的としています。

前提知識の解説

  • Goコンパイラ (cmd/gc): Go言語の公式コンパイラの一部であり、Goソースコードを機械語に変換する主要なツールです。
  • 字句解析 (Lexical Analysis): ソースコードをトークン(単語や記号の最小単位)のストリームに変換するプロセス。
  • 構文解析 (Parsing): トークンのストリームを解析し、言語の文法規則に従って抽象構文木(AST)を構築するプロセス。
  • 抽象構文木 (Abstract Syntax Tree - AST): ソースコードの構造を木構造で表現したもの。コンパイラの各フェーズでコードの分析や変換に利用されます。
  • Bison: GNUプロジェクトが開発しているパーサジェネレータ。文法定義ファイル(.yファイル)からC言語のパーサコード(.tab.c.tab.hファイル)を自動生成します。Goコンパイラのフロントエンドの一部で利用されていました。
  • go.y: Go言語の文法定義が記述されたBisonの入力ファイル。
  • y.tab.c / y.tab.h: go.yからBisonによって生成されるC言語のパーサコード。
  • Node: Goコンパイラ内部でASTの各要素を表すデータ構造。各ノードは、そのコード要素がソースコードのどの位置にあるかを示す行番号情報を持つことが重要です。
  • ONAME, ONONAME, OTYPE, OPACK, OLITERAL: Goコンパイラ内部で定義されているASTノードの操作コード(opcode)。これらはそれぞれ、名前、非名前(未解決の名前)、型、パッケージ、リテラルを表します。
  • OPAREN: 括弧を表すASTノードの操作コード。このコミットでは、行番号情報を持たないノードに正しい行番号を付与するために、このノードがラッパーとして導入されています。
  • implicit: ASTノードのフラグで、そのノードがソースコードに明示的に記述されたものではなく、コンパイラによって暗黙的に生成されたものであることを示します。

技術的詳細

このコミットの主要な変更点は、Goコンパイラのパーサー(Bisonによって生成されたコード)がASTノードを構築する際に、特定の種類のノードに対して行番号情報を正しく付与するように修正されたことです。

具体的には、src/cmd/gc/go.yファイルにおいて、simple_stmt(単純な文)とbare_complitexpr(裸の複合リテラル式)の文法規則に修正が加えられています。

以前のパーサーでは、ONAME(名前)、ONONAME(未解決の名前)、OTYPE(型)、OPACK(パッケージ)、OLITERAL(リテラル)といったノードが式として単独で使用された場合、それらのノード自体が行番号情報を持たないことがありました。このため、これらのノードに関連するエラーメッセージ(例えば「not used」メッセージ)が、ソースコード上の正しい行に紐付けられないという問題が発生していました。

この修正では、これらの行番号情報を持たないノードが式として現れた場合、それらをOPARENノードでラップするように変更されています。OPARENノードは、その子ノードの行番号情報を継承するか、あるいは自身の生成時に正しい行番号を付与されるため、結果としてラッパーされたノードも正しい行番号を持つことになります。

さらに、このOPARENノードにはimplicit = 1というフラグが設定されます。これは、このノードがソースコードに明示的に記述された括弧ではなく、コンパイラが内部的に生成したものであることを示します。このフラグは、後続のコンパイラフェーズで、ASTの構造を分析する際に、明示的な括弧と暗黙的な括弧を区別するために使用されます。

また、src/cmd/gc/y.tab.cファイルには、Bisonのバージョンが2.5から2.3にダウングレードされた痕跡が見られます。通常、ソフトウェアは新しいバージョンにアップグレードされるものですが、このケースではダウングレードが行われています。これは、Bison 2.5で導入された特定の機能や変更が、Goコンパイラの既存のコードベースやビルドシステムと互換性がなかった、あるいは予期せぬ問題を引き起こしたため、安定した旧バージョンに戻すという判断がなされた可能性があります。Bison 2.5は、名前付き参照、新しいパーサーテーブルタイプ(IELR(1)やcanonical LR(1))、改善されたエラーハンドリングなど、多くの新機能が導入されています。これらの新機能が当時のGoコンパイラの開発方針や既存のコードと合致しなかった、あるいは安定性に問題があったため、よりシンプルな2.3に戻したと考えられます。

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

src/cmd/gc/go.y

--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -405,6 +405,20 @@ simple_stmt:
 		$$ = $1;
+
+		// These nodes do not carry line numbers.
+		// Since a bare name used as an expression is an error,
+		// introduce a wrapper node to give the correct line.
+		switch($$->op) {
+		case ONAME:
+		case ONONAME:
+		case OTYPE:
+		case OPACK:
+		case OLITERAL:
+			$$ = nod(OPAREN, $$, N);
+			$$->implicit = 1;
+			break;
+		}
 	}
 |	expr LASOP expr
 	{
@@ -989,6 +1003,7 @@ bare_complitexpr:
 		case OPACK:
 		case OLITERAL:
 			$$ = nod(OPAREN, $$, N);
+			$$->implicit = 1;
 		}
 	}
 |	'{' start_complit braced_keyval_list '}'

src/cmd/gc/y.tab.c

Bisonのバージョン情報が2.5から2.3に変更されています。

--- a/src/cmd/gc/y.tab.c
+++ b/src/cmd/gc/y.tab.c
@@ -1,21 +1,24 @@
-/* A Bison parser, made by GNU Bison 2.5.  */
+/* A Bison parser, made by GNU Bison 2.3.  */

コアとなるコードの解説

src/cmd/gc/go.yの変更

simple_stmtbare_complitexprのルール内で、$$ = $1;(または同様の代入)の後に新しいコードブロックが追加されています。

		// These nodes do not carry line numbers.
		// Since a bare name used as an expression is an error,
		// introduce a wrapper node to give the correct line.
		switch($$->op) {
		case ONAME:
		case ONONAME:
		case OTYPE:
		case OPACK:
		case OLITERAL:
			$$ = nod(OPAREN, $$, N);
			$$->implicit = 1;
			break;
		}

このコードブロックは、現在のASTノード($$)の操作コード(op)をチェックします。もしそのノードがONAME, ONONAME, OTYPE, OPACK, OLITERALのいずれかである場合、これらのノードは単独では行番号情報を持たない可能性があるため、nod(OPAREN, $$, N)を呼び出して新しいOPARENノードを作成し、現在のノードをその子として設定します。そして、この新しいOPARENノードが$$に代入されます。

$$->implicit = 1;という行は、この新しく作成されたOPARENノードが、ソースコードに明示的に書かれた括弧ではなく、コンパイラによって暗黙的に挿入されたものであることを示します。これにより、コンパイラの他の部分がこのノードを適切に処理できるようになります。

この変更により、これらの特定の種類のノードが式として使用された場合でも、それらをラップするOPARENノードが正しい行番号情報を持つため、コンパイラが生成するエラーメッセージ(特に「not used」メッセージ)が、ソースコード上の正確な位置を指し示すようになります。

src/cmd/gc/y.tab.cの変更

このファイルはBisonによって自動生成されるため、手動で編集されることは稀です。しかし、このコミットではBisonのバージョンが2.5から2.3にダウングレードされたことが示されています。これは、go.yファイルがBison 2.3で再生成されたことを意味します。

このダウングレードは、Bison 2.5が導入した新機能や変更が、Goコンパイラのビルドプロセスやランタイム動作に問題を引き起こした可能性を示唆しています。例えば、Bison 2.5は新しいパーサーテーブルの生成方法やエラー処理の改善を含んでいましたが、これらがGoコンパイラの既存のコードベースと完全に互換性がなかったり、予期せぬパフォーマンス問題やバグを発生させたりしたのかもしれません。安定性を優先し、よりシンプルなBison 2.3に戻すことで、コンパイラの信頼性を確保したと考えられます。

関連リンク

  • Go Issue #4663: https://github.com/golang/go/issues/4663 (ただし、検索結果では直接的な情報が見つからなかったため、このリンクは一般的なGoのIssueトラッカーへのリンクとして提示します。実際のIssueはアーカイブされているか、別の番号に統合されている可能性があります。)
  • Go言語のコンパイラに関するドキュメント (公式): https://go.dev/doc/
  • GNU Bison 公式サイト: https://www.gnu.org/software/bison/

参考にした情報源リンク