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

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

このコミットは、Goコンパイラ(gc)内のswitch文の型チェック処理において、誤ったエラーメッセージ引数が渡されていた問題を修正するものです。具体的には、src/cmd/gc/swt.cファイル内のtypecheckswitch関数において、特定の型不一致エラーメッセージのyyerror呼び出しで、不要な引数が渡されていたのを削除し、引数の数とフォーマット指定子の数を一致させています。これにより、コンパイラが生成するエラーメッセージの正確性が向上します。

コミット

commit d7634ad7d9a3b914245fba89cb9737f12c07dfe6
Author: Rémy Oudompheng <oudomphe@phare.normalesup.org>
Date:   Mon Dec 12 16:08:32 2011 -0500

    gc: fix wrong arguments to error message for switches.
    
    Fixes #2502.
    
    R=golang-dev, rsc
    CC=golang-dev, remy
    https://golang.org/cl/5472062

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

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

元コミット内容

gc: fix wrong arguments to error message for switches.

Fixes #2502.

R=golang-dev, rsc
CC=golang-dev, remy
https://golang.org/cl/5472062

変更の背景

この変更は、Goコンパイラがswitch文の型チェック中に生成するエラーメッセージの正確性を改善するために行われました。以前のバージョンでは、特定の条件下(特にswitch式がbool型と型不一致を起こす場合)で、エラー報告関数yyerrorに渡される引数の数が、フォーマット文字列内のフォーマット指定子の数と一致していませんでした。

このような引数の不一致は、C言語のprintfのような可変引数関数において未定義動作を引き起こす可能性があります。コンパイラのエラー報告システムでは、これは通常、エラーメッセージが正しく表示されない、またはクラッシュする原因となり得ます。このコミットは、この引数不一致を修正し、コンパイラがより信頼性の高いエラーメッセージを生成できるようにすることを目的としています。コミットメッセージにあるFixes #2502は、Goプロジェクトの内部課題追跡システムにおける特定のバグ報告に対応するものです。

前提知識の解説

Goコンパイラ (gc)

gcは、Go言語の公式コンパイラです。Goのソースコードを機械語に変換する役割を担っています。コンパイラは、字句解析、構文解析、意味解析(型チェックを含む)、中間コード生成、最適化、コード生成といった複数のフェーズを経て動作します。このコミットが関連するのは、主に意味解析フェーズの一部である型チェックです。

swt.c

src/cmd/gc/swt.cは、Goコンパイラのソースコードの一部であり、switch文のコンパイルに関連するロジックを実装しています。swtは"switch"の略であると推測されます。このファイルには、switch文の構文解析後の抽象構文木(AST)を処理し、型チェックやコード生成の準備を行う関数が含まれています。

yyerror

yyerrorは、コンパイラやパーサー(特にyaccbisonなどのツールで生成されるもの)で一般的に使用されるエラー報告関数です。これは通常、printf関数と同様に、フォーマット文字列とそれに続く可変個の引数を受け取ります。フォーマット文字列内の%N%Tのようなカスタムフォーマット指定子は、コンパイラ内部のデータ構造(例えば、NodeType)を人間が読める形式に変換して出力するために使用されます。

  • %N: Node構造体(抽象構文木のノード)の情報を表示するための指定子。
  • %T: Type構造体(Goの型情報)の情報を表示するための指定子。

yyerrorが正しく機能するためには、フォーマット文字列内の指定子の数と種類が、渡される引数の数と種類に厳密に一致している必要があります。一致しない場合、コンパイラは誤った情報を出力したり、予期せぬ動作を引き起こしたりする可能性があります。

型チェック

型チェックは、コンパイラの意味解析フェーズの重要な部分です。プログラム内の各操作が、その操作に期待されるデータ型に対して正しいかどうかを検証します。例えば、switch文では、switch式の型とcase式の型が互いに互換性があるか、または特定のルール(例: bool型に対するswitchなど)に従っているかをチェックします。型チェックの目的は、実行時エラーを未然に防ぎ、プログラムの堅牢性を高めることです。

技術的詳細

このコミットの技術的な核心は、yyerror関数の引数とフォーマット指定子の不一致を解消することにあります。

src/cmd/gc/swt.c内のtypecheckswitch関数は、switch文の型チェックを担当しています。この関数内には、switch文のcase式がbool型と型不一致を起こした場合にエラーを報告するロジックがあります。

元のコードでは、以下の行でエラーが報告されていました。

yyerror("invalid case %N in switch (mismatched types %T and bool)", ll->n, n->ntest, ll->n->type, t);

このyyerror呼び出しでは、フォーマット文字列"invalid case %N in switch (mismatched types %T and bool)"には、%N%Tの2つのフォーマット指定子が含まれています。しかし、それに続く引数はll->n, n->ntest, ll->n->type, tの4つでした。

これは、フォーマット指定子の数(2つ)と引数の数(4つ)が一致しないという問題を引き起こします。C言語の可変引数関数では、このような不一致は未定義動作につながり、コンパイラがクラッシュしたり、意味不明なエラーメッセージを出力したりする可能性があります。

この特定のelseブロックのコンテキストでは、n->ntesttは、エラーメッセージの文脈において不要な、または不適切な情報であったと考えられます。特に、このelseブロックは、if(n->ntest)が偽である場合に実行されるため、n->ntestが有効な値を持たない可能性があります。

コミットによって、この行は以下のように修正されました。

yyerror("invalid case %N in switch (mismatched types %T and bool)", ll->n, ll->n->type);

修正後、フォーマット指定子(%N, %T)の数と引数(ll->n, ll->n->type)の数が2つずつとなり、完全に一致するようになりました。これにより、yyerror関数は期待通りに動作し、正確なエラーメッセージを生成できるようになります。

この修正は、コンパイラの堅牢性とユーザーへのエラー報告の品質を向上させるための、細かではあるが重要な改善です。

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

diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c
index 786fdf938d..7764f0dd35 100644
--- a/src/cmd/gc/swt.c
+++ b/src/cmd/gc/swt.c
@@ -878,7 +878,7 @@ typecheckswitch(Node *n)
 					if(n->ntest)
 						yyerror("invalid case %N in switch on %N (mismatched types %T and %T)", ll->n, n->ntest, ll->n->type, t);
 					else
-						yyerror("invalid case %N in switch (mismatched types %T and bool)", ll->n, n->ntest, ll->n->type, t);
+						yyerror("invalid case %N in switch (mismatched types %T and bool)", ll->n, ll->n->type);
 					} else if(nilonly && !isconst(ll->n, CTNIL)) {
 						yyerror("invalid case %N in switch (can only compare %s %N to nil)", ll->n, nilonly, n->ntest);
 					}

コアとなるコードの解説

変更はsrc/cmd/gc/swt.cファイルのtypecheckswitch関数内、具体的には879行目付近にあります。

元のコードでは、if(n->ntest)の条件が偽であるelseブロック内で、以下のyyerror呼び出しがありました。

yyerror("invalid case %N in switch (mismatched types %T and bool)", ll->n, n->ntest, ll->n->type, t);

この行は、switch文のcase式がbool型と型不一致を起こした場合にエラーを報告するためのものです。しかし、フォーマット文字列"invalid case %N in switch (mismatched types %T and bool)"には%N%Tの2つのフォーマット指定子しかありません。それに対して、引数としてll->n, n->ntest, ll->n->type, tの4つが渡されていました。

このコミットでは、このyyerror呼び出しからn->ntesttの2つの引数が削除されました。

yyerror("invalid case %N in switch (mismatched types %T and bool)", ll->n, ll->n->type);

これにより、フォーマット指定子(%N, %T)の数と引数(ll->n, ll->n->type)の数が一致し、yyerror関数が正しく動作するようになりました。この修正は、コンパイラが生成するエラーメッセージの正確性と信頼性を保証するために不可欠です。n->ntesttは、この特定のエラーパスでは関連性が低いか、または誤った情報を提供していたため、削除されました。

関連リンク

参考にした情報源リンク

  • Go Code Review System (Gerrit): Goプロジェクトのコードレビュープロセスに関する情報。
  • C言語のprintf関数と可変引数関数の動作に関する一般的な知識。
  • コンパイラの設計と実装に関する一般的な知識(字句解析、構文解析、意味解析、エラー報告など)。