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

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

このコミットは、Go言語の初期のコンパイラ(gc)における2つのマイナーなバグ修正を含んでいます。具体的には、シンボル再宣言のロジックと、any型(Goの初期段階における特殊な型)の使用制限に関する修正が行われています。これらの修正は、コンパイラの正確性と堅牢性を向上させることを目的としています。

コミット

commit 7dd62cb3bc51222076506132f5d409ec7fa58b38
Author: Ken Thompson <ken@golang.org>
Date:   Wed Dec 10 12:38:16 2008 -0800

    2 minor bugs
    
    R=r
    OCL=20906
    CL=20906

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

https://github.com/golang/go/commit/7dd62cb3bc51222076506132f5d409ec7fa58b38

元コミット内容

    2 minor bugs
    
    R=r
    OCL=20906
    CL=20906

変更の背景

このコミットは、Go言語の初期開発段階(2008年12月)に行われたもので、Go言語がまだ一般に公開される前の内部開発フェーズに当たります。当時のGoコンパイラは、C言語で書かれたgc(Go Compiler)という名称のツールチェーンの一部でした。

変更の背景には、以下の2つの具体的な問題があったと考えられます。

  1. シンボル再宣言のロジックの誤り: src/cmd/gc/dcl.cにおけるredeclare関数は、シンボル(変数、関数など)が現在のスコープブロック内で再宣言された場合にエラーを報告する役割を担っていました。しかし、元の実装では、シンボルが現在のブロックに属していない場合にエラーを報告するという、意図とは逆のロジックになっていました。これにより、本来エラーとすべき再宣言が見過ごされたり、逆に正当な宣言が誤ってエラーとされたりする可能性がありました。
  2. any型の使用制限の不備: src/cmd/gc/go.yはGo言語の文法定義ファイルであり、any型に関する制約が記述されていました。any型は、Go言語の初期段階における特殊な型であり、後のinterface{}(空インターフェース)やany(Go 1.18以降の型パラメータ)の前身、あるいはコンパイラ内部での特殊な用途の型であった可能性があります。この型は通常の使用が制限されるべきでしたが、特定の内部パッケージ(PACKAGEという名前のパッケージ)では例外的に許可される必要があったと考えられます。元の実装では、この例外処理が考慮されておらず、PACKAGEパッケージ内でのany型の使用が不適切に制限されていた可能性があります。

これらのバグは、コンパイラの正確な動作を妨げ、Go言語のセマンティクスを正しく反映できない原因となっていたため、修正が必要でした。

前提知識の解説

このコミットを理解するためには、以下の前提知識が必要です。

  • Go言語の初期コンパイラ gc:
    • Go言語の最初の公式コンパイラは、C言語で書かれたgc(Go Compiler)というツールチェーンでした。これは、Plan 9 Cコンパイラをベースにしていました。
    • src/cmd/gcディレクトリは、このコンパイラのソースコードが置かれていた場所です。
  • コンパイラのフェーズ:
    • 字句解析 (Lexical Analysis): ソースコードをトークンに分解する。
    • 構文解析 (Syntax Analysis): トークン列が文法規則に合致するかをチェックし、抽象構文木 (AST) を構築する。go.yのようなYacc/Bisonファイルがこのフェーズで使用される。
    • 意味解析 (Semantic Analysis): 型チェック、スコープ解決、シンボル解決などを行う。dcl.cのようなファイルがこのフェーズに関わる。
    • コード生成 (Code Generation): 実行可能なコードを生成する。
  • Yacc/Bison:
    • go.yファイルは、Yacc (Yet Another Compiler Compiler) またはそのGNU版であるBisonで生成されるパーサーの文法定義ファイルです。.y拡張子はYacc/Bisonの入力ファイルを示します。
    • 文法規則と、それらの規則がマッチしたときに実行されるC言語のアクションコードが記述されています。
    • $$は現在の規則のセマンティック値、$1などは規則の右辺の各要素のセマンティック値を参照します。
    • yyerrorは、構文解析中にエラーが発生した際に呼び出される関数で、エラーメッセージを出力します。
  • シンボルテーブルとスコープ:
    • コンパイラは、プログラム内で宣言された変数、関数、型などの「シンボル」に関する情報を「シンボルテーブル」に格納します。
    • 「スコープ」は、シンボルが有効なプログラムの領域を指します。Go言語では、ブロック({}で囲まれた領域)ごとにスコープが形成されます。
    • Sym構造体はシンボルを表し、blockフィールドはシンボルが宣言されたブロックの識別子、lastlinenoは最後に宣言された行番号を保持していると考えられます。
  • any型 (初期Go言語):
    • Go言語の初期には、現在のinterface{}(空インターフェース)に相当する概念がanyというキーワードで表現されていた時期があった、あるいはコンパイラ内部で特殊な型として扱われていた可能性があります。
    • Go 1.18で導入されたanyキーワードは、interface{}のエイリアスですが、このコミットの時期とは異なります。このコミットにおけるany型は、よりプリミティブな、コンパイラ内部の概念であった可能性が高いです。
  • strcmp関数: C言語の標準ライブラリ関数で、2つの文字列を比較します。strcmp(s1, s2) == 0は、s1s2が等しいことを意味します。

技術的詳細

src/cmd/gc/dcl.c の修正

このファイルは、Goコンパイラの宣言(declaration)処理、特にシンボル管理とスコープ解決に関連する部分を扱っています。redeclare関数は、シンボルが再宣言された場合の処理を担当します。

元のコードのロジックは以下の通りでした。

if(s->block != block) { // シンボルsが現在のブロックとは異なるブロックで宣言されている場合
    s->block = block;
    s->lastlineno = lineno;
    return; // 新しいブロックでの宣言として処理し、関数を終了
}
// ここに到達するのは、s->block == block の場合、つまり同じブロックで再宣言された場合
yyerror("%s %S redeclared in this block %d", str, s, block); // エラーを報告
print("\tprevious declaration at %L\\n", s->lastlineno);

このロジックは、コメントと実際の動作が逆になっていました。if(s->block != block)の条件が真の場合(異なるブロックでの宣言)、それは再宣言ではなく、新しいスコープでの有効な宣言であるべきです。しかし、その場合はreturnしてしまい、エラー報告は行われません。逆に、if文を通過してエラー報告が行われるのは、s->block == blockの場合、つまり同じブロックでの再宣言の場合です。これは正しい動作ですが、if文の条件が混乱を招いていました。

修正後のコードは以下の通りです。

if(s->block == block) { // シンボルsが現在のブロックと同じブロックで宣言されている場合
    yyerror("%s %S redeclared in this block", str, s); // エラーを報告
    print("\tprevious declaration at %L\\n", s->lastlineno);
}
// ここに到達するのは、s->block == block の場合はエラー報告後、
// s->block != block の場合はif文をスキップして直接ここに来る
s->block = block; // シンボルのブロック情報を現在のブロックに更新
s->lastlineno = lineno; // シンボルの最終宣言行を現在の行に更新

この修正により、ロジックが明確になりました。

  1. s->block == blockの場合のみ、再宣言エラーを報告します。
  2. エラー報告の有無にかかわらず、s->blocks->lastlinenoは常に現在のブロックと行番号に更新されます。これは、シンボルが新しいブロックで宣言された場合(s->block != block)でも、その新しい宣言情報を正しく記録するために必要です。 また、エラーメッセージから%d(ブロック番号)が削除され、より簡潔になっています。

src/cmd/gc/go.y の修正

このファイルはGo言語の文法をYacc形式で定義しており、構文解析中に特定のセマンティックアクションを実行します。修正箇所はnametypeという文法規則に関連しています。

元のコードは以下の通りでした。

nametype:
    LATYPE
    {
        if($1->otype != T && $1->otype->etype == TANY) // $1が型であり、その型がTANYである場合
            yyerror("the any type is restricted"); // "any typeは制限されています"とエラー
        $$ = oldtype($1);
    }
;

この規則は、LATYPE(おそらく型名を表すトークン)が解析されたときに実行されます。$1LATYPEのセマンティック値を参照し、その型情報(otypeetype)をチェックしています。TANYは、コンパイラ内部でany型を表す定数であると考えられます。

修正後のコードは以下の通りです。

nametype:
    LATYPE
    {
        if($1->otype != T && $1->otype->etype == TANY)
        if(strcmp(package, "PACKAGE") != 0) // 現在のパッケージ名が"PACKAGE"でない場合
            yyerror("the any type is restricted");
        $$ = oldtype($1);
    }
;

追加された条件if(strcmp(package, "PACKAGE") != 0)は、any型が制限されるのは、現在のパッケージ名が文字列"PACKAGE"と異なる場合のみであることを意味します。これは、PACKAGEという名前のパッケージが、any型を特別に許可される内部的な、あるいはブートストラップ的なパッケージであったことを示唆しています。この修正により、特定の内部パッケージでのany型の正当な使用が誤ってエラーとなるのを防ぎ、コンパイラの柔軟性と正確性を向上させています。

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

src/cmd/gc/dcl.c

--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -701,13 +701,12 @@ testdclstack(void)
 static void
 redeclare(char *str, Sym *s)
 {
-	if(s->block != block) {
-		s->block = block;
-		s->lastlineno = lineno;
-		return;
-	}
-	yyerror("%s %S redeclared in this block %d", str, s, block);
-	print("\tprevious declaration at %L\\n\", s->lastlineno);
+	if(s->block == block) {
+		yyerror("%s %S redeclared in this block", str, s);
+		print("\tprevious declaration at %L\\n", s->lastlineno);
+	}
+	s->block = block;
+	s->lastlineno = lineno;
 }
 
 void

src/cmd/gc/go.y

--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -1087,6 +1087,7 @@ nametype:
 	LATYPE
 	{
 		if($1->otype != T && $1->otype->etype == TANY)
+\t\tif(strcmp(package, "PACKAGE") != 0)
 		\tyyerror("the any type is restricted");
 		$$ = oldtype($1);
 	}

コアとなるコードの解説

src/cmd/gc/dcl.credeclare 関数

この関数は、シンボルsstrという名前で再宣言されたかどうかをチェックし、必要に応じてエラーを報告します。

  • 変更前:
    • if(s->block != block): シンボルsが現在のスコープブロックblockとは異なるブロックで宣言されている場合、それは再宣言ではなく、新しいスコープでの有効な宣言と見なされ、s->blocks->lastlinenoを更新して関数を終了していました。
    • このifブロックを通過した場合(つまりs->block == blockの場合)、同じブロック内での再宣言と判断し、yyerrorでエラーメッセージを出力していました。しかし、このロジックは直感的ではなく、if文の条件が逆転しているように見えました。
  • 変更後:
    • if(s->block == block): シンボルsが現在のスコープブロックblockと同じブロックで既に宣言されている場合、これは明確な再宣言エラーです。yyerrorを呼び出してエラーメッセージを出力します。エラーメッセージから不要なブロック番号の表示が削除され、より簡潔になりました。
    • s->block = block; s->lastlineno = lineno;: この2行はifブロックの外に移動しました。これにより、シンボルが同じブロックで再宣言された場合(エラー報告後)でも、新しいブロックで宣言された場合(if文をスキップ)でも、常にシンボルのブロック情報と最終宣言行が現在の情報に更新されるようになりました。これは、シンボルが有効な宣言として処理された場合に、その最新の宣言情報をシンボルテーブルに反映させるために重要です。

この修正により、シンボル再宣言の検出ロジックがより正確かつ堅牢になり、コンパイラがGo言語のスコープ規則を正しく適用できるようになりました。

src/cmd/gc/go.ynametype 規則

この部分は、Go言語の文法定義ファイルにおけるnametypeという規則のアクションブロックです。nametypeは、型名が解析されたときに実行される処理を定義しています。

  • 変更前:
    • if($1->otype != T && $1->otype->etype == TANY): 解析された型($1で参照される)が、コンパイラ内部でTANYとして定義されている特殊な型であるかどうかをチェックしていました。もしそうであれば、yyerror("the any type is restricted")を呼び出し、any型の使用が制限されていることを示すエラーを出力していました。
  • 変更後:
    • if($1->otype != T && $1->otype->etype == TANY): 既存のany型チェックはそのままです。
    • if(strcmp(package, "PACKAGE") != 0): 新たにこの条件が追加されました。これは、現在のコンパイル対象のパッケージ名が文字列"PACKAGE"と等しくない場合にのみ、内側のyyerrorが実行されるようにします。
      • package変数は、現在のコンパイル対象のパッケージ名を表すグローバル変数またはコンテキスト変数であると推測されます。
      • strcmp(package, "PACKAGE") != 0は、「現在のパッケージ名が"PACKAGE"ではない」という条件を意味します。
    • この二重のif文により、any型がTANYであり、かつ現在のパッケージが"PACKAGE"ではない場合にのみ、エラーが報告されるようになりました。

この修正は、any型が特定の内部パッケージ("PACKAGE")でのみ許可されるという、Go言語の初期設計における特殊な要件に対応したものです。これにより、コンパイラは言語のセマンティクスをより正確に強制できるようになりました。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • Yacc/Bisonの一般的な使用方法に関する情報
  • C言語の標準ライブラリ関数strcmpに関する情報
  • Go言語のGitHubリポジトリのコミット履歴
  • Go言語の初期コンパイラgcに関する歴史的資料(Web検索を通じて得られた情報)

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

このコミットは、Go言語の初期のコンパイラ(gc)における2つのマイナーなバグ修正を含んでいます。具体的には、シンボル再宣言のロジックと、any型(Goの初期段階における特殊な型)の使用制限に関する修正が行われています。これらの修正は、コンパイラの正確性と堅牢性を向上させることを目的としています。

コミット

commit 7dd62cb3bc51222076506132f5d409ec7fa58b38
Author: Ken Thompson <ken@golang.org>
Date:   Wed Dec 10 12:38:16 2008 -0800

    2 minor bugs
    
    R=r
    OCL=20906
    CL=20906

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

https://github.com/golang/go/commit/7dd62cb3bc51222076506132f5d409ec7fa58b38

元コミット内容

    2 minor bugs
    
    R=r
    OCL=20906
    CL=20906

変更の背景

このコミットは、Go言語の初期開発段階(2008年12月)に行われたもので、Go言語がまだ一般に公開される前の内部開発フェーズに当たります。当時のGoコンパイラは、C言語で書かれたgc(Go Compiler)という名称のツールチェーンの一部でした。

変更の背景には、以下の2つの具体的な問題があったと考えられます。

  1. シンボル再宣言のロジックの誤り: src/cmd/gc/dcl.cにおけるredeclare関数は、シンボル(変数、関数など)が現在のスコープブロック内で再宣言された場合にエラーを報告する役割を担っていました。しかし、元の実装では、シンボルが現在のブロックに属していない場合にエラーを報告するという、意図とは逆のロジックになっていました。これにより、本来エラーとすべき再宣言が見過ごされたり、逆に正当な宣言が誤ってエラーとされたりする可能性がありました。
  2. any型の使用制限の不備: src/cmd/gc/go.yはGo言語の文法定義ファイルであり、any型に関する制約が記述されていました。any型は、Go言語の初期段階における特殊な型であり、後のinterface{}(空インターフェース)やany(Go 1.18以降の型パラメータ)の前身、あるいはコンパイラ内部での特殊な用途の型であった可能性があります。この型は通常の使用が制限されるべきでしたが、特定の内部パッケージ(PACKAGEという名前のパッケージ)では例外的に許可される必要があったと考えられます。元の実装では、この例外処理が考慮されておらず、PACKAGEパッケージ内でのany型の使用が不適切に制限されていた可能性があります。

これらのバグは、コンパイラの正確な動作を妨げ、Go言語のセマンティクスを正しく反映できない原因となっていたため、修正が必要でした。

前提知識の解説

このコミットを理解するためには、以下の前提知識が必要です。

  • Go言語の初期コンパイラ gc:
    • Go言語の最初の公式コンパイラは、C言語で書かれたgc(Go Compiler)というツールチェーンでした。これは、Plan 9 Cコンパイラをベースにしていました。
    • src/cmd/gcディレクトリは、このコンパイラのソースコードが置かれていた場所です。現在のGoコンパイラはGo言語で書かれており、src/cmd/compile/internal/typecheck/dcl.goのようなファイルが宣言処理を担当しています。このコミットは、Go言語がまだC言語で実装されていた非常に初期の段階のものであることに注意が必要です。
  • コンパイラのフェーズ:
    • 字句解析 (Lexical Analysis): ソースコードをトークンに分解する。
    • 構文解析 (Syntax Analysis): トークン列が文法規則に合致するかをチェックし、抽象構文木 (AST) を構築する。go.yのようなYacc/Bisonファイルがこのフェーズで使用される。
    • 意味解析 (Semantic Analysis): 型チェック、スコープ解決、シンボル解決などを行う。dcl.cのようなファイルがこのフェーズに関わる。
    • コード生成 (Code Generation): 実行可能なコードを生成する。
  • Yacc/Bison:
    • go.yファイルは、Yacc (Yet Another Compiler Compiler) またはそのGNU版であるBisonで生成されるパーサーの文法定義ファイルです。.y拡張子はYacc/Bisonの入力ファイルを示します。
    • 文法規則と、それらの規則がマッチしたときに実行されるC言語のアクションコードが記述されています。
    • $$は現在の規則のセマンティック値、$1などは規則の右辺の各要素のセマンティック値を参照します。
    • yyerrorは、構文解析中にエラーが発生した際に呼び出される関数で、エラーメッセージを出力します。
  • シンボルテーブルとスコープ:
    • コンパイラは、プログラム内で宣言された変数、関数、型などの「シンボル」に関する情報を「シンボルテーブル」に格納します。
    • 「スコープ」は、シンボルが有効なプログラムの領域を指します。Go言語では、ブロック({}で囲まれた領域)ごとにスコープが形成されます。
    • Sym構造体はシンボルを表し、blockフィールドはシンボルが宣言されたブロックの識別子、lastlinenoは最後に宣言された行番号を保持していると考えられます。
  • any型 (初期Go言語):
    • Go言語の初期には、現在のinterface{}(空インターフェース)に相当する概念がanyというキーワードで表現されていた時期があった、あるいはコンパイラ内部で特殊な型として扱われていた可能性があります。
    • Go 1.18で導入されたanyキーワードは、interface{}のエイリアスですが、このコミットの時期とは異なります。このコミットにおけるany型は、よりプリミティブな、コンパイラ内部の概念であった可能性が高いです。
  • strcmp関数: C言語の標準ライブラリ関数で、2つの文字列を比較します。strcmp(s1, s2) == 0は、s1s2が等しいことを意味します。

技術的詳細

src/cmd/gc/dcl.c の修正

このファイルは、Goコンパイラの宣言(declaration)処理、特にシンボル管理とスコープ解決に関連する部分を扱っています。redeclare関数は、シンボルが再宣言された場合の処理を担当します。

元のコードのロジックは以下の通りでした。

if(s->block != block) { // シンボルsが現在のブロックとは異なるブロックで宣言されている場合
    s->block = block;
    s->lastlineno = lineno;
    return; // 新しいブロックでの宣言として処理し、関数を終了
}
// ここに到達するのは、s->block == block の場合、つまり同じブロックで再宣言された場合
yyerror("%s %S redeclared in this block %d", str, s, block); // エラーを報告
print("\tprevious declaration at %L\\n", s->lastlineno);

このロジックは、コメントと実際の動作が逆になっていました。if(s->block != block)の条件が真の場合(異なるブロックでの宣言)、それは再宣言ではなく、新しいスコープでの有効な宣言であるべきです。しかし、その場合はreturnしてしまい、エラー報告は行われません。逆に、if文を通過してエラー報告が行われるのは、s->block == blockの場合、つまり同じブロックでの再宣言の場合です。これは正しい動作ですが、if文の条件が混乱を招いていました。

修正後のコードは以下の通りです。

if(s->block == block) { // シンボルsが現在のブロックと同じブロックで宣言されている場合
    yyerror("%s %S redeclared in this block", str, s); // エラーを報告
    print("\tprevious declaration at %L\\n", s->lastlineno);
}
// ここに到達するのは、s->block == block の場合はエラー報告後、
// s->block != block の場合はif文をスキップして直接ここに来る
s->block = block; // シンボルのブロック情報を現在のブロックに更新
s->lastlineno = lineno; // シンボルの最終宣言行を現在の行に更新

この修正により、ロジックが明確になりました。

  1. s->block == blockの場合のみ、再宣言エラーを報告します。
  2. エラー報告の有無にかかわらず、s->blocks->lastlinenoは常に現在のブロックと行番号に更新されます。これは、シンボルが新しいブロックで宣言された場合(s->block != block)でも、その新しい宣言情報を正しく記録するために必要です。 また、エラーメッセージから%d(ブロック番号)が削除され、より簡潔になっています。

src/cmd/gc/go.y の修正

このファイルはGo言語の文法をYacc形式で定義しており、構文解析中に特定のセマンティックアクションを実行します。修正箇所はnametypeという文法規則に関連しています。

元のコードは以下の通りでした。

nametype:
    LATYPE
    {
        if($1->otype != T && $1->otype->etype == TANY) // $1が型であり、その型がTANYである場合
            yyerror("the any type is restricted"); // "any typeは制限されています"とエラー
        $$ = oldtype($1);
    }
;

この規則は、LATYPE(おそらく型名を表すトークン)が解析されたときに実行されます。$1LATYPEのセマンティック値を参照し、その型情報(otypeetype)をチェックしています。TANYは、コンパイラ内部でany型を表す定数であると考えられます。

修正後のコードは以下の通りです。

nametype:
    LATYPE
    {
        if($1->otype != T && $1->otype->etype == TANY)
        if(strcmp(package, "PACKAGE") != 0) // 現在のパッケージ名が"PACKAGE"でない場合
            yyerror("the any type is restricted");
        $$ = oldtype($1);
    }
;

追加された条件if(strcmp(package, "PACKAGE") != 0)は、any型が制限されるのは、現在のパッケージ名が文字列"PACKAGE"と異なる場合のみであることを意味します。これは、PACKAGEという名前のパッケージが、any型を特別に許可される内部的な、あるいはブートストラップ的なパッケージであったことを示唆しています。この修正により、特定の内部パッケージでのany型の正当な使用が誤ってエラーとなるのを防ぎ、コンパイラの柔軟性と正確性を向上させています。

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

src/cmd/gc/dcl.c

--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -701,13 +701,12 @@ testdclstack(void)
 static void
 redeclare(char *str, Sym *s)
 {
-	if(s->block != block) {
-		s->block = block;
-		s->lastlineno = lineno;
-		return;
-	}
-	yyerror("%s %S redeclared in this block %d", str, s, block);
-	print("\tprevious declaration at %L\\n\", s->lastlineno);
+	if(s->block == block) {
+		yyerror("%s %S redeclared in this block", str, s);
+		print("\tprevious declaration at %L\\n", s->lastlineno);
+	}
+	s->block = block;
+	s->lastlineno = lineno;
 }
 
 void

src/cmd/gc/go.y

--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -1087,6 +1087,7 @@ nametype:
 	LATYPE
 	{
 		if($1->otype != T && $1->otype->etype == TANY)
+\t\tif(strcmp(package, "PACKAGE") != 0)
 		\tyyerror("the any type is restricted");
 		$$ = oldtype($1);
 	}

コアとなるコードの解説

src/cmd/gc/dcl.credeclare 関数

この関数は、シンボルsstrという名前で再宣言されたかどうかをチェックし、必要に応じてエラーを報告します。

  • 変更前:
    • if(s->block != block): シンボルsが現在のスコープブロックblockとは異なるブロックで宣言されている場合、それは再宣言ではなく、新しいスコープでの有効な宣言と見なされ、s->blocks->lastlinenoを更新して関数を終了していました。
    • このifブロックを通過した場合(つまりs->block == blockの場合)、同じブロック内での再宣言と判断し、yyerrorでエラーメッセージを出力していました。しかし、このロジックは直感的ではなく、if文の条件が逆転しているように見えました。
  • 変更後:
    • if(s->block == block): シンボルsが現在のスコープブロックblockと同じブロックで既に宣言されている場合、これは明確な再宣言エラーです。yyerrorを呼び出してエラーメッセージを出力します。エラーメッセージから不要なブロック番号の表示が削除され、より簡潔になりました。
    • s->block = block; s->lastlineno = lineno;: この2行はifブロックの外に移動しました。これにより、シンボルが同じブロックで再宣言された場合(エラー報告後)でも、新しいブロックで宣言された場合(if文をスキップ)でも、常にシンボルのブロック情報と最終宣言行が現在の情報に更新されるようになりました。これは、シンボルが有効な宣言として処理された場合に、その最新の宣言情報をシンボルテーブルに反映させるために重要です。

この修正により、シンボル再宣言の検出ロジックがより正確かつ堅牢になり、コンパイラがGo言語のスコープ規則を正しく適用できるようになりました。

src/cmd/gc/go.ynametype 規則

この部分は、Go言語の文法定義ファイルにおけるnametypeという規則のアクションブロックです。nametypeは、型名が解析されたときに実行される処理を定義しています。

  • 変更前:
    • if($1->otype != T && $1->otype->etype == TANY): 解析された型($1で参照される)が、コンパイラ内部でTANYとして定義されている特殊な型であるかどうかをチェックしていました。もしそうであれば、yyerror("the any type is restricted")を呼び出し、any型の使用が制限されていることを示すエラーを出力していました。
  • 変更後:
    • if($1->otype != T && $1->otype->etype == TANY): 既存のany型チェックはそのままです。
    • if(strcmp(package, "PACKAGE") != 0): 新たにこの条件が追加されました。これは、現在のコンパイル対象のパッケージ名が文字列"PACKAGE"と等しくない場合にのみ、内側のyyerrorが実行されるようにします。
      • package変数は、現在のコンパイル対象のパッケージ名を表すグローバル変数またはコンテキスト変数であると推測されます。
      • strcmp(package, "PACKAGE") != 0は、「現在のパッケージ名が"PACKAGE"ではない」という条件を意味します。
    • この二重のif文により、any型がTANYであり、かつ現在のパッケージが"PACKAGE"ではない場合にのみ、エラーが報告されるようになりました。

この修正は、any型が特定の内部パッケージ("PACKAGE")でのみ許可されるという、Go言語の初期設計における特殊な要件に対応したものです。これにより、コンパイラは言語のセマンティクスをより正確に強制できるようになりました。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • Yacc/Bisonの一般的な使用方法に関する情報
  • C言語の標準ライブラリ関数strcmpに関する情報
  • Go言語のGitHubリポジトリのコミット履歴
  • Web検索結果: "Go compiler src/cmd/gc dcl.c redeclare" (Go言語のコンパイラがC言語からGo言語に移行したことに関する情報)