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

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

このコミットは、Goコンパイラ(cmd/gc)におけるエラー報告の挙動を改善するものです。具体的には、コンパイル中に他のエラーが既に発生している場合、「mark left on the stack」という特定のエラーメッセージが重複して報告されるのを防ぎます。これにより、コンパイラのエラー出力がより明確になり、開発者が問題の根本原因を特定しやすくなります。

コミット

commit cd2eb4872223073ad00c6b06371c1ffcbad8fb63
Author: Russ Cox <rsc@golang.org>
Date:   Tue Jul 30 10:27:26 2013 -0400

    cmd/gc: don't report mark if other things are broken
    
    Fixes #5598.
    
    R=ken2
    CC=golang-dev
    https://golang.org/cl/12104043

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

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

元コミット内容

cmd/gc: don't report mark if other things are broken

Fixes #5598.

R=ken2
CC=golang-dev
https://golang.org/cl/12104043

変更の背景

この変更は、Goコンパイラ(cmd/gc)が特定の状況下で冗長なエラーメッセージを報告するバグ(Issue 5598)を修正するために行われました。

Goコンパイラは、コードの解析中に内部的なスタック(dclstack)を使用して、宣言やスコープに関する情報を管理しています。このスタックには、特定のポイントを示す「マーク」がプッシュされることがあります。通常、これらのマークは対応する処理が完了した時点でポップされるべきです。

しかし、コンパイル中に他の致命的なエラーが発生した場合、コンパイラはエラー処理ルーチンに入り、その後の処理を中断することがあります。この際、dclstack上にマークが残ったままになることがありました。この残されたマークは、testdclstack関数によって「mark left on the stack」というエラーとして報告されます。

問題は、この「mark left on the stack」エラーが、既に発生している他のエラーの「結果」として生じる場合がある点です。つまり、根本的なエラーが先にあり、そのエラーによってコンパイラの内部状態が不正になり、結果としてマークがスタックに残ってしまうという連鎖的な問題でした。このような場合、根本的なエラーメッセージと「mark left on the stack」というメッセージの両方が報告され、開発者にとっては後者のメッセージが根本原因を特定する上でノイズとなる可能性がありました。

このコミットの目的は、既に他のエラーが報告されている場合には、「mark left on the stack」というメッセージの報告を抑制することで、コンパイラのエラー出力をより簡潔かつ有用にすることです。

前提知識の解説

Goコンパイラ (cmd/gc)

cmd/gcは、Go言語の公式コンパイラです。Goのソースコードを機械語に変換する役割を担っています。コンパイルプロセスは、字句解析、構文解析、意味解析、中間コード生成、最適化、コード生成など、複数のフェーズに分かれています。

dcl.c

src/cmd/gc/dcl.cは、Goコンパイラの宣言(declaration)処理に関連する部分のソースファイルです。変数、関数、型などの宣言の解析と管理を担当しています。このファイルには、スコープの管理やシンボルテーブルへのエントリ追加など、コンパイラの重要な内部処理が含まれています。

dclstack

dclstackは、Goコンパイラの内部で使用されるスタック構造です。主に、現在のスコープや宣言のコンテキストを追跡するために使用されます。例えば、関数定義に入るときやブロックに入るときに、新しいスコープを示す「マーク」がこのスタックにプッシュされ、スコープを抜けるときにポップされます。これにより、コンパイラは変数の可視性や名前解決を正しく行うことができます。

nerrors

nerrorsは、Goコンパイラがコンパイル中に検出したエラーの数を追跡するためのグローバル変数です。この変数の値が0でない場合、コンパイル中に少なくとも1つのエラーが発生したことを意味します。コンパイラは通常、nerrorsが0でない場合に、最終的にコンパイルを中止し、エラーメッセージを出力します。

yyerror

yyerrorは、Goコンパイラがエラーメッセージを出力するために使用する内部関数です。この関数が呼び出されると、エラーメッセージが標準エラー出力に表示され、同時にnerrorsカウンタが増加します。

errorexit()

errorexit()は、Goコンパイラが致命的なエラーを検出した際に、コンパイルプロセスを終了させるために呼び出される関数です。この関数が呼び出されると、コンパイラは直ちに終了し、通常は非ゼロの終了コードを返します。

技術的詳細

このコミットは、src/cmd/gc/dcl.cファイル内のtestdclstack関数に2行のコードを追加することで、エラー報告のロジックを変更しています。

testdclstack関数は、コンパイルプロセスの終了時や特定のチェックポイントで呼び出され、dclstackが正しい状態にあるか(つまり、プッシュされたマークがすべてポップされているか)を検証します。もしマークがスタックに残っている場合、それは通常、コンパイラの内部的な不整合を示しており、「mark left on the stack」というエラーが報告されます。

変更前のコードでは、dclstackにマークが残っていることが検出されると、無条件にyyerror("mark left on the stack")が呼び出されていました。

変更後のコードでは、yyerrorの呼び出しの前に、nerrors変数の値がチェックされるようになりました。

		if(d->name == nil) {
			if(nerrors != 0)
				errorexit();
			yyerror("mark left on the stack");
			continue;
		}

この変更のポイントは以下の通りです。

  1. if(nerrors != 0): この条件は、既に他のコンパイルエラーが検出されているかどうかをチェックします。
  2. errorexit();: もしnerrorsが0でなければ(つまり、他のエラーが既に存在すれば)、errorexit()が呼び出されます。errorexit()はコンパイラを即座に終了させるため、その後のyyerror("mark left on the stack")の呼び出しは実行されません。

これにより、コンパイル中に既に他のエラーが発生している場合、testdclstack関数は「mark left on the stack」というエラーを報告する代わりに、コンパイラを即座に終了させます。これは、根本的なエラーが既に報告されており、この「mark left on the stack」エラーがその結果として生じたものである可能性が高いと判断されるためです。この修正により、開発者は根本的なエラーメッセージに集中できるようになります。

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

変更はsrc/cmd/gc/dcl.cファイルのtestdclstack関数内、141行目に追加された2行です。

--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -141,6 +141,8 @@ testdclstack(void)
 
 	for(d=dclstack; d!=S; d=d->link) {
 		if(d->name == nil) {
+			if(nerrors != 0)
+				errorexit();
 			yyerror("mark left on the stack");
 			continue;
 		}

コアとなるコードの解説

追加された2行は、dclstack上にマークが残っている(d->name == nil)と判断された場合に実行されるロジックを変更します。

  • if(nerrors != 0): この行は、グローバル変数nerrorsをチェックし、コンパイル中に既に何らかのエラーが報告されているかどうかを確認します。
  • errorexit();: もしnerrorsが0でなければ、つまり他のエラーが既に存在する場合は、errorexit()関数が呼び出されます。この関数はコンパイラの実行を直ちに終了させます。

このロジックにより、「mark left on the stack」というエラーが、他のより重要なエラーの「結果」として発生している場合に、その冗長なエラーメッセージの報告が抑制されます。コンパイラは、既にエラー状態にあることを認識し、これ以上処理を続けても意味がないと判断して終了します。これにより、開発者は根本的なエラーに集中でき、エラーメッセージのノイズが減ります。

関連リンク

参考にした情報源リンク

  • Go Issue Tracker: https://github.com/golang/go/issues
  • Go Code Review (Gerrit): https://go-review.googlesource.com/
  • Go言語のソースコード(特にsrc/cmd/gc/ディレクトリ)
  • コンパイラの設計と実装に関する一般的な知識
  • C言語の基本的な構文と制御フロー
  • スタックデータ構造に関する知識
  • エラーハンドリングの原則# [インデックス 16925] ファイルの概要

このコミットは、Goコンパイラ(cmd/gc)におけるエラー報告の挙動を改善するものです。具体的には、コンパイル中に他のエラーが既に発生している場合、「mark left on the stack」という特定のエラーメッセージが重複して報告されるのを防ぎます。これにより、コンパイラのエラー出力がより明確になり、開発者が問題の根本原因を特定しやすくなります。

コミット

commit cd2eb4872223073ad00c6b06371c1ffcbad8fb63
Author: Russ Cox <rsc@golang.org>
Date:   Tue Jul 30 10:27:26 2013 -0400

    cmd/gc: don't report mark if other things are broken
    
    Fixes #5598.
    
    R=ken2
    CC=golang-dev
    https://golang.org/cl/12104043

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

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

元コミット内容

cmd/gc: don't report mark if other things are broken

Fixes #5598.

R=ken2
CC=golang-dev
https://golang.org/cl/12104043

変更の背景

この変更は、Goコンパイラ(cmd/gc)が特定の状況下で冗長なエラーメッセージを報告するバグ(Issue 5598)を修正するために行われました。

Goコンパイラは、コードの解析中に内部的なスタック(dclstack)を使用して、宣言やスコープに関する情報を管理しています。このスタックには、特定のポイントを示す「マーク」がプッシュされることがあります。通常、これらのマークは対応する処理が完了した時点でポップされるべきです。

しかし、コンパイル中に他の致命的なエラーが発生した場合、コンパイラはエラー処理ルーチンに入り、その後の処理を中断することがあります。この際、dclstack上にマークが残ったままになることがありました。この残されたマークは、testdclstack関数によって「mark left on the stack」というエラーとして報告されます。

問題は、この「mark left on the stack」エラーが、既に発生している他のエラーの「結果」として生じる場合がある点です。つまり、根本的なエラーが先にあり、そのエラーによってコンパイラの内部状態が不正になり、結果としてマークがスタックに残ってしまうという連鎖的な問題でした。このような場合、根本的なエラーメッセージと「mark left on the stack」というメッセージの両方が報告され、開発者にとっては後者のメッセージが根本原因を特定する上でノイズとなる可能性がありました。

このコミットの目的は、既に他のエラーが報告されている場合には、「mark left on the stack」というメッセージの報告を抑制することで、コンパイラのエラー出力をより簡潔かつ有用にすることです。

前提知識の解説

Goコンパイラ (cmd/gc)

cmd/gcは、Go言語の公式コンパイラです。Goのソースコードを機械語に変換する役割を担っています。コンパイルプロセスは、字句解析、構文解析、意味解析、中間コード生成、最適化、コード生成など、複数のフェーズに分かれています。

dcl.c

src/cmd/gc/dcl.cは、Goコンパイラの宣言(declaration)処理に関連する部分のソースファイルです。変数、関数、型などの宣言の解析と管理を担当しています。このファイルには、スコープの管理やシンボルテーブルへのエントリ追加など、コンパイラの重要な内部処理が含まれています。

dclstack

dclstackは、Goコンパイラの内部で使用されるスタック構造です。主に、現在のスコープや宣言のコンテキストを追跡するために使用されます。例えば、関数定義に入るときやブロックに入るときに、新しいスコープを示す「マーク」がこのスタックにプッシュされ、スコープを抜けるときにポップされます。これにより、コンパイラは変数の可視性や名前解決を正しく行うことができます。

nerrors

nerrorsは、Goコンパイラがコンパイル中に検出したエラーの数を追跡するためのグローバル変数です。この変数の値が0でない場合、コンパイル中に少なくとも1つのエラーが発生したことを意味します。コンパイラは通常、nerrorsが0でない場合に、最終的にコンパイルを中止し、エラーメッセージを出力します。

yyerror

yyerrorは、Goコンパイラがエラーメッセージを出力するために使用する内部関数です。この関数が呼び出されると、エラーメッセージが標準エラー出力に表示され、同時にnerrorsカウンタが増加します。

errorexit()

errorexit()は、Goコンパイラが致命的なエラーを検出した際に、コンパイルプロセスを終了させるために呼び出される関数です。この関数が呼び出されると、コンパイラは直ちに終了し、通常は非ゼロの終了コードを返します。

技術的詳細

このコミットは、src/cmd/gc/dcl.cファイル内のtestdclstack関数に2行のコードを追加することで、エラー報告のロジックを変更しています。

testdclstack関数は、コンパイルプロセスの終了時や特定のチェックポイントで呼び出され、dclstackが正しい状態にあるか(つまり、プッシュされたマークがすべてポップされているか)を検証します。もしマークがスタックに残っている場合、それは通常、コンパイラの内部的な不整合を示しており、「mark left on the stack」というエラーが報告されます。

変更前のコードでは、dclstackにマークが残っていることが検出されると、無条件にyyerror("mark left on the stack")が呼び出されていました。

変更後のコードでは、yyerrorの呼び出しの前に、nerrors変数の値がチェックされるようになりました。

		if(d->name == nil) {
			if(nerrors != 0)
				errorexit();
			yyerror("mark left on the stack");
			continue;
		}

この変更のポイントは以下の通りです。

  1. if(nerrors != 0): この条件は、既に他のコンパイルエラーが検出されているかどうかをチェックします。
  2. errorexit();: もしnerrorsが0でなければ(つまり、他のエラーが既に存在すれば)、errorexit()が呼び出されます。errorexit()はコンパイラを即座に終了させるため、その後のyyerror("mark left on the stack")の呼び出しは実行されません。

これにより、コンパイル中に既に他のエラーが発生している場合、testdclstack関数は「mark left on the stack」というエラーを報告する代わりに、コンパイラを即座に終了させます。これは、根本的なエラーが既に報告されており、この「mark left on the stack」エラーがその結果として生じたものである可能性が高いと判断されるためです。この修正により、開発者は根本的なエラーメッセージに集中できるようになります。

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

変更はsrc/cmd/gc/dcl.cファイルのtestdclstack関数内、141行目に追加された2行です。

--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -141,6 +141,8 @@ testdclstack(void)
 
 	for(d=dclstack; d!=S; d=d->link) {
 		if(d->name == nil) {
+			if(nerrors != 0)
+				errorexit();
 			yyerror("mark left on the stack");
 			continue;
 		}

コアとなるコードの解説

追加された2行は、dclstack上にマークが残っている(d->name == nil)と判断された場合に実行されるロジックを変更します。

  • if(nerrors != 0): この行は、グローバル変数nerrorsをチェックし、コンパイル中に既に何らかのエラーが報告されているかどうかを確認します。
  • errorexit();: もしnerrorsが0でなければ、つまり他のエラーが既に存在する場合は、errorexit()関数が呼び出されます。この関数はコンパイラの実行を直ちに終了させます。

このロジックにより、「mark left on the stack」というエラーが、他のより重要なエラーの「結果」として発生している場合に、その冗長なエラーメッセージの報告が抑制されます。コンパイラは、既にエラー状態にあることを認識し、これ以上処理を続けても意味がないと判断して終了します。これにより、開発者は根本的なエラーに集中でき、エラーメッセージのノイズが減ります。

関連リンク

参考にした情報源リンク

  • Go Issue Tracker: https://github.com/golang/go/issues
  • Go Code Review (Gerrit): https://go-review.googlesource.com/
  • Go言語のソースコード(特にsrc/cmd/gc/ディレクトリ)
  • コンパイラの設計と実装に関する一般的な知識
  • C言語の基本的な構文と制御フロー
  • スタックデータ構造に関する知識
  • エラーハンドリングの原則