エラーメッセージ定义を掘り下げる

ここではSwiftのコンパイルエラーのメッセージ定义を改めて掘り下げる。

defッセージ定义は.defファイルの中でこのような形で书かれている。

 错误(extra_rbrace,none, 
“顶级的外部'}'”,()

ERRORの他にWARNING AR NOTEもあるが形は同じである。

そ利用方法に応じて様々な形に変えられる。その変换处理は#define机能を使って非常に复雑に(どこが走っているかわかりにくい状态で)行われる。

.defファイルには,それぞれ対応する.hファイルがあり,まずはそのペアのつながりで.defファイルがどう利用されるかを见ていく。

.defファイルと.hファイルのペアというの例,例えば

DiagnosticsParse.def

に対して

DiagnosticsParse.h

があるということ。

.defファイルの中身は

  #ifndef错误 
#定义ERROR(ID,Options,Text,Signature)\
诊断(错误,ID,选项,文本,签名)
#endifそれぞれのメッセージ定义が大量#ifndef DIAG_NO_UNDEF
#如果已定义(DIAG)
#undef DIAG
# 万一
#undef错误
#万一

となっている。ポイントを挙げると

  • ファイルの头で, ERRORがすでに#defineされているかどうかを确认し,されていない场合には#defineを行い, ERRORDIAGに置き换える设定をする(引数の表记は省略)。
  • 一个々のメッセージ定义の后,最后にDIAG_NO_UNDEFの状态によりdefine状态の消去を行う。

ちなみに, WARNINGNOTEが构造がERRORと同じなので省いてある,ここから先も同じ。

h .hファイルの中身は

  #include“ swift / AST / DiagnosticsCommon.h”#定义DIAG(KIND,ID,Options,Text,Signature)\ 
外部详细信息:: DiagWithArguments ::类型ID;
#include“ DiagnosticsParse.def”
  • DIAG#defineされて,
    extern detail::DiagWithArguments::type ID;
    になる。
  • defの后で.defファイルが#includeされる。

h,この.hファイルを読み込んだ场合は,

ERROR -> DIAG -> detail::DiagWith~

という変换がされる。その过程は,

  • .hファイル内でERROR#defineされていないので,.defファイル内でERRORDIAGへの#defineが有效になり,
  • DIAのDIAGが.hファイル先头の#defineによりdetail::DiagWith~に置き换えられる。

となる。

また, DIAG_NO_UNDEF#defineされていないので,.defファイルの最后でdefine状态が消される。

Common.hとCommon.def

.hをよく见るとDiagnosticsCommon.hを#includeしている。このDiagnosticsCommon.h(とそのペアのDiagnosticsCommon.def)は,コンパイルの中で泛用的に利用されるもの。やっていることは上と同じで

ERROR -> DIAG -> detail::DiagWith~

の変换を行い,最后に定义状态を消す。


DiagnosticsAll.defである。これを见て。ァててていく。

  #ifndef错误 
#定义ERROR(ID,Options,Text,Signature)\
诊断(错误,ID,选项,文本,签名)
#endif#define DIAG_NO_UNDEF#include“ DiagnosticsCommon.def”
#include“ DiagnosticsParse.def”
#include“ DiagnosticsSema.def”
#include“ DiagnosticsClangImporter.def”
#include“ DiagnosticsSIL.def”
#include“ DiagnosticsIRGen.def”
#include“ DiagnosticsFrontend.def”
#include“ DiagnosticsDriver.def”
#include“ DiagnosticsRefactoring.def” #undef DIAG_NO_UNDEF#如果已定义(DIAG)
#undef DIAG
#万一
#undef错误

んのDiagnosticsAll.defは全ての.defファイルを読み込むものである。真ん中の#includeの连続で読み込んでいる。

  • 先头でERROR#defineされているか确认し,されていなければERRORからDIAGへの変换を设定している。
  • これは,各.defファイルを読み込む前にDIAG_NO_UNDEF#defineしている。これは各.defファイル内でERROR#defineを消さないようにするためである。
  • 各.defファイル内では,すでにERROR#defineされている场合は再#defineしないので,このDiagnosticsAll.defの先头のERROR#defineが全体に渡り有效である。
  • DiagnosticsAll.defファイルの最后では例によって#defineしたものを削除している。

DiagnosticsAll.defを読むところ

DiagnosticsAll.defDiagnosticsAll.defを読むところはどこか。

  • /lib/AST/DiagnosticEngine.cpp
  • /lib/AST/DiagnosticList.cpp

である。

/lib/AST/DiagnosticEngine.cppについて

DiagnosticsAll.def#includeしているところを见ていく。

枚举LocalDiagID:uint32_t

 枚举LocalDiagID:uint32_t { 
#define DIAG(种类,ID,选项,文本,签名)ID,
#include“ swift / AST / DiagnosticsAll.def”
NumDiags
};

LocalDiagIDという枚举を宣言している。ここではDIAGからIDを取Di出す#defineをしてからDiagnosticsAll.defを読みこんでいて

ERROR -> DIAG -> IDのみ

という変换が行われる。

きラー识别文字列によるenumを作って,ひとつひとつに数値を与えていることがわかる。0から顺番に番号が振られて,最后のNumDiagsに个数が入る。

静态StoredDiagnosticInfostoredDiagnosticInfos []

 静态StoredDiagnosticInfostoredDiagnosticInfos [] = { 
#定义错误(ID,选项,文本,签名)\
StoredDiagnosticInfo(DiagnosticKind :: Error,DiagnosticOptions :: Options),#include“ swift / AST / DiagnosticsAll.def”
};

StoredDiagnosticInfoの配列を宣言しているStoredDiagnosticInfoについては未开拓者。

ここではERROR#defineしているので

ERROR -> StoredDiagnosticInfo

ここでERROR#defineされると,この先でERRORの上书き#defineはされない。DIAGを経由しないでERRORを直接料理している。

静态const char * diagnosticStrings []

 静态const char * diagnosticStrings [] = { 
#define错误(ID,选项,文本,签名),
#include“ swift / AST / DiagnosticsAll.def”
“ ”,
};

ここはText部分を取り出して配列を作るところ。上と同じようにERRORの直接料理で,

ERROR -> Textのみ

という変换がされる。

/lib/AST/DiagnosticList.cppについて

次にもう一つのほう,DiagnosticList.cppを见ていく。

枚举类swift :: DiagID:uint32_t

 枚举类swift :: DiagID:uint32_t { 
#定义DIAG(种类,ID,选项,文本,签名)ID,
#include“ swift / AST / DiagnosticsAll.def”
};

ここもエラー识别文字列によるenumを作って,ひとつひとつに数値を与えていることがわかる。

detail :: DiagWithArguments ::类型ID

  #定义DIAG(种类,ID,选项,文本,签名)\ 
detail :: DiagWithArguments :: type ID = {DiagID :: ID};
#include“ swift / AST / DiagnosticsAll.def”

ここも置き换え。

 外部细节:: DiagWithArguments  ::类型ID = {DiagID :: ID}; 

に変换される。

このtypeは/include/swift/AST/DiagnosticsCommon.hで

  template  
结构DiagWithArguments; template
结构DiagWithArguments {
类型定义Diag 类型;
};

と定义されているが深そうなので,一旦切り上げる。

以上,メッセージ定义がどういう形になっていくかを见てきた。当然ここから先も调べる项目は残されている。调べたらまた记事にしたいと思う。

内容に间违いがあった场合,お知らせ下さい。