/*	
 *	include/assert.h
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2012-2017 Naoyuki Sawa
 *
 *	* Thu Jul 20 06:10:41 JST 2006 Naoyuki Sawa
 *	- 新規作成。
 *	  本ファイルを作成した理由は、clipstd.hのコメントを参照してください。
 *	* Tue Jan 03 22:25:06 JST 2012 Naoyuki Sawa
 *	- assertの有効/無効を、NDEBUGシンボルで切り替えるように変更しました。
 *	* Sat Jan 14 00:03:29 JST 2012 Naoyuki Sawa
 *	- assertマクロが、die()の代りに、die3()を使用するように変更しました。
 *	  詳細は、clipmisc.hの同日のコメントを参照してください。
 *	* Wed Nov 18 21:37:53 JST 2015 Naoyuki Sawa
 *	- 'extern "C" {'〜'}'で囲みました。.cppを含むWin32プロジェクトからもインクルード出来るようにするためです。
 *	* Sun Oct 23 10:04:30 JST 2016 Naoyuki Sawa
 *	- _Static_assertとstatic_assertを追加しました。
 *	  これまではstatic_assertが無かったために、静的な検査を実行時に行っている処理が各モジュール内に幾つか有るのですが、
 *	  今回static_assertを追加したので、各モジュール内の上記のような処理を、順次static_assertに置き換えて行く予定です。
 *	* Thu Nov 17 21:56:29 JST 2016 Naoyuki Sawa
 *	- assert()マクロの実装を変更しました。(変更したファイルは、clippce.cとinclude/assert.hです。)
 *	  詳細は、clippce.c内のnew_assert_isr()の実装部のコメントを参照して下さい。
 *	* Fri Dec 02 22:30:56 JST 2016 Naoyuki Sawa
 *	- assert()が使用するソフトウェア例外の番号を、0番⇒3番に変更しました。
 *	  変更した理由の詳細は、clippce.c内の「assert()マクロのサポートルーチン」の同日のコメントを参照して下さい。
 *	* Thu Jun 29 21:22:51 JST 2017 Naoyuki Sawa
 *	- _Static_assertの定義を修正しました。
 *	  修正した理由は、以下の通りです。
 *	- 修正前の_Static_assertの定義行のコメントにて、
 *	  ＞同じtypedef名(この場合は__Static_assert__)を複数回使用しても、同じ定義内容ならばエラーにならない事を利用しています。
 *	  と書いたのですが、それは誤りでした。
 *	  VC++6.0やVS2017ではC言語ソースでもC++ソースでもエラーにならなかったのですが、P/ECE開発環境のGCCでは同じtypedef名を複数回使用すると同じ定義内容でもエラーになる事がわかったからです。
 *	  どうやら、同じtypedef名を同じ定義内容で複数回使用した場合、C言語ではエラーになり、C++ではエラーにならないのが仕様のようです。
 *	  ⇒参考資料「Stack Overflow - Repeated typedefs - invalid in C but valid in C++?」(https://stackoverflow.com/questions/8594954/repeated-typedefs-invalid-in-c-but-valid-in-c)
 *	  VC++6.0やVS2017ではC言語ソースでもエラーになりませんでしたが、本来はC言語ではエラーになるのが正しいので、VC++6.0やVS2017特有の拡張仕様だと思います。
 *	- 修正方法は単純で、変更前はtypedefを利用していた部分を、externに置き換えただけです。
 *	  externならば、同じ変数名を同じ定義内容で複数回使用しても、C言語でもC++でもエラーにならない事は明らかです。
 *	  今回の修正によって、VC++6.0やVS2017のC言語ソースでもC++ソースでも、P/ECE開発環境のGCCでも、正しく動作するようになりました。
 *	- 尚、本物の_Static_assertは、C言語でも関数の途中に書けるようですが、当実装ではC言語で関数の途中に書く場合は括弧で囲む必要が有る事に注意して下さい。
 *	  C言語では、関数の途中にextern宣言を書く事は出来ないからです。(変更前のtypedefでも同様でした。)
 *	  上記の点が、本物の_Static_assertとは非互換ですが、仕方がありません。
 *	- 「□static_assertの使用例」を追加しました。
 *	  今回の修正によって、各処理系で正しく動作するようになった事を確認するためのテストスイートです。
 *	  今後、もし、また_Static_assertを修正した場合も、「□static_assertの使用例」で動作確認をして下さい。
 *	* Fri Jun 30 21:44:43 JST 2017 Naoyuki Sawa
 *	- 昨日(2017/06/29)、_Static_assertの定義を修正した影響で、P/ECE開発環境のGCCで警告が出るようになっていた問題に気付き、再度、修正しました。
 *	  具体的には、以下の通りです。
 *	- 関数スコープ外で一度もstatic_assertを使用せず、関数スコープ内でstatic_assertを使用すると、以下の警告が表示されていました。
 *	  ＞warning: unused variable `__Static_assert__'
 *	  上記の警告が表示される原因は、どうやらGCCは、関数内でextern宣言した変数がその関数内で使用されなかった場合も、関数内で実体を定義した変数が使用されなかった場合と同様に、警告を表示するようだからです。
 *	  │//例
 *	  │void test() {
 *	  │  extern int dummy; //⇒warning: unused variable `dummy'
 *	  │}
 *	  警告を回避する方法としては、二種類の方法が有ります。
 *	  一種類目の方法は、関数内で実体を定義した変数が使用しない場合の警告回避と同様に、__attribute__((unused))属性を指定する事です。
 *	  │//例
 *	  │void test() {
 *	  │  extern int dummy __attribute__((unused)); //⇒警告は表示されません。
 *	  │}
 *	  二種類目の方法は、関数内でextern宣言して使用しない変数よりも先に、グローバルスコープで同じ名前の変数をextern宣言する事です。
 *	  │//例
 *	  │extern int dummy;
 *	  │void test() {
 *	  │  extern int dummy; //⇒警告は表示されません。
 *	  │}
 *	  今回のstatic_assertの警告回避には、どちらの方法を取っても良いのですが、一種類目の方法の方が明示的で判り易いと思うので、一種類目の方法を取る事にしました。
 *	  尚、VC++6.0やVS2017では、関数内でextern宣言した変数がその関数内で使用されなくても警告は表示されないので、上記の対策を行う必要は有りません。
 */
#ifndef _ASSERT_H
#define _ASSERT_H

#ifdef  __cplusplus
extern "C" {
#endif//__cplusplus

//{{2012/01/03:変更
//#define assert	ASSERT	/* ASSERT()マクロはclipmisc.hで定義されています。 */
//↓2012/01/03:変更
//↓* Tue Jan 03 22:25:06 JST 2012 Naoyuki Sawa
//↓- これまで、assertはASSERTと同じく、DEBUGシンボルが定義されているときに有効としていました。
//↓  しかし、CLiP使用プロジェクトをDEBUGビルドすることはほとんど無いため、assertもASSERTもほぼ使い道がありませんでした。
//↓  元々DEBUGシンボルは、CLiPライブラリ開発初期のDEBUGビルドに利用したのみで、現在はDEBUGビルドの検証は行っていません。
//↓- 今回、Luaライブラリの使用にあたり、APIチェックがassertで行われているため、assertを有効にしたいと考えました。
//↓  しかし、上記の理由により、CLiP使用プロジェクトでassertを有効にすることは難しいという問題が発生しました。
//↓  assertを有効にしたければ、DEBUGビルドにするしか方法が無く、実用的でないためです。
//↓- そこで今後、assertはASSERTと違って、NDEBUGシンボルが定義されていないときに有効とするように変更しました。
//↓  標準Cライブラリの仕様に準拠するようにしたわけで、その観点からも望ましいはずです。
//↓- 個別のCLiP使用プロジェクトでassertを有効にしたい場合、DEBUGビルドにする必要はありません。
//↓  個別のCLiP使用プロジェクトのMakefileで、以下のように定義してください。
//↓	APP_CFLAGS = -D"NDEBUG -UNDEBUG"
//↓  これは、gcc33.exeに対して以下のように引き渡され、clip.mk内で指定されている-DNDEBUGを、未定義に戻します。
//↓	gcc33.exe -S -x c -Wall -DPIECE -I..\clip -I..\clip\include -O2 -DNDEBUG -DNDEBUG -UNDEBUG -IC:\usr\PIECE\include main.$
//↓	                                                                         ~~~~~~~~~~~~~~~~~
//↓  単純に「APP_CFLAGS = -UNDEBUG」と指定できない理由は、pcc33.exeが-Uオプションを認識しないからです。
//↓  このテクニックについては、test.pce/Makefile内のコメントを参照してください。
#ifndef NDEBUG
//{{2012/01/14:変更
//void die(const char* fmt, ...) __attribute__((noreturn));
//#define assert(f)	((void)((f) || (die(__FILE__ "(%d): %s", __LINE__, #f), 0)))
//↓2012/01/14:変更
//void die3(const char* file, int line, const char* f) __attribute__((noreturn));
//#define assert(f)	((void)((f) || (die3(__FILE__, __LINE__, #f), 0)))
//↓2016/11/17変更:assert()マクロの実装を変更しました。(変更したファイルは、clippce.cとinclude/assert.hです。)
//#define assert(expr)	asm /*volatile*/ ("ld.w\t%%r9,%0\n\tint\t0\n\t.word\t%1\n\t.half\t%2" : : "r"(expr),"i"(__FILE__),"i"(__LINE__) : /*"cc",*/"%r9")	//展開コードの詳細については、clippce.c内のnew_assert_isr()の実装部のコメントを参照して下さい。
//			//  ~~~~~~~~~~~~出力オペランドが無いasmは暗黙でvolatileと見なされるので明示不要。   ~~~ポインタも"m"ではなく"i"で指定する事に注意せよ。"m"で指定するとポインタへのポインタに展開されてしまう。
//↓2016/12/02変更:assert()が使用するソフトウェア例外の番号を、0番⇒3番に変更しました。
#define assert(expr)	asm /*volatile*/ ("ld.w\t%%r9,%0\n\tint\t3\n\t.word\t%1\n\t.half\t%2" : : "r"(expr),"i"(__FILE__),"i"(__LINE__) : /*"cc",*/"%r9")	//展開コードの詳細については、clippce.c内のnew_assert_isr()の実装部のコメントを参照して下さい。
			//  ~~~~~~~~~~~~出力オペランドが無いasmは暗黙でvolatileと見なされるので明示不要。   ~~~ポインタも"m"ではなく"i"で指定する事に注意せよ。"m"で指定するとポインタへのポインタに展開されてしまう。
//}}2016/12/02変更:assert()が使用するソフトウェア例外の番号を、0番⇒3番に変更しました。
#else /*NDEBUG*/
#define assert(f)	((void)0)
#endif/*NDEBUG*/
//}}2012/01/03:変更

//{{2016/10/23追加:_Static_assertとstatic_assertを追加しました。
//───────────────────────────────────────────────────────────────
//□参照資料「cppreference.com - static assert declaration」(http://en.cppreference.com/w/c/language/_Static_assert)
//│C > C language > Declarations
//│static assert declaration
//│Syntax
//│　_Static_assert(expression,message)	(since C11)
//│　expression - any integer constant expression
//│　message    - any string literal
//│　This keyword is also available as convenience macro 「static_assert」(http://en.cppreference.com/w/c/error/static_assert), available in the header <assert.h>.
//│Explanation
//│　The constant expression is evaluated at compile time and compared to zero.
//│　If it compares equal to zero, a compile-time error occurs and the compiler must display message as part of the error message (except that characters not in basic source character set aren't required to be displayed).
//│　Otherwise, if expression does not equal zero, nothing happens; no code is emitted.
//│Keywords
//│　「_Static_assert」(http://en.cppreference.com/w/c/keyword/_Static_assert)
//│Example
//│　│#include <assert.h>
//│　│int main(void) {
//│　│　//Test if math works.
//│　│　static_assert(2 + 2 == 4, "Whoa dude!"); //or _Static_assert(...
//│　│　//This will produce an error at compile time.
//│　│　static_assert(sizeof(int) < sizeof(char), "this program requires that int is less than char");
//│　│}
//│References
//│　・C11 standard (ISO/IEC 9899:2011):
//│　　・6.7.10 Static assertions (p: 145)
//│　　・7.2 Diagnostics <assert.h> (p: 186-187)
//│See also
//│　「C++ documentation」(http://en.cppreference.com/w/cpp/language/static_assert) for Static Assertion
//{{2017/06/29変更:_Static_assertの定義を修正しました。
//#define _Static_assert(expression,message) typedef char __Static_assert__[(expression)?1:-1]	//厳密には'_Static_assert'はC11のキーワードであってマクロではないのですが、当ライブラリではマクロとして実装する事にしました。マクロでの実装方法については、「Windows Dev Center - C_ASSERT macro」(https://msdn.microsoft.com/en-us/library/windows/desktop/ms679289(v=vs.85).aspx)を参考にしました。同じtypedef名(この場合は__Static_assert__)を複数回使用しても、同じ定義内容ならばエラーにならない事を利用しています。
//↓2017/06/29変更:_Static_assertの定義を修正しました。
//#define _Static_assert(expression,message) extern char __Static_assert__[(expression)?1:-1]	//厳密には'_Static_assert'はC11のキーワードであってマクロではないのですが、当ライブラリではマクロとして実装する事にしました。マクロでの実装方法については、「Windows Dev Center - C_ASSERT macro」(https://msdn.microsoft.com/en-us/library/windows/desktop/ms679289(v=vs.85).aspx)を参考にしました。typedefではなくexternを使用した理由については、当ファイル(include/assert.h)の先頭の、'Thu Jun 29 21:22:51 JST 2017 Naoyuki Sawa'のコメントを参照して下さい。
//↓2017/06/30変更:昨日(2017/06/29)、_Static_assertの定義を修正した影響で、P/ECE開発環境のGCCで警告が出るようになっていた問題に気付き、再度、修正しました。
#ifndef __GNUC__
//□Win32,及び,その他全般の場合
#define _Static_assert(expression,message) extern char __Static_assert__[(expression)?1:-1]	//厳密には'_Static_assert'はC11のキーワードであってマクロではないのですが、当ライブラリではマクロとして実装する事にしました。マクロでの実装方法については、「Windows Dev Center - C_ASSERT macro」(https://msdn.microsoft.com/en-us/library/windows/desktop/ms679289(v=vs.85).aspx)を参考にしました。typedefではなくexternを使用した理由については、当ファイル(include/assert.h)の先頭の、'Thu Jun 29 21:22:51 JST 2017 Naoyuki Sawa'のコメントを参照して下さい。
#else //__GNUC__
//□P/ECEの場合
#define _Static_assert(expression,message) extern char __Static_assert__[(expression)?1:-1] __attribute__((unused))	//'__attribute__((unused))'が必要な理由については、当ファイル(include/assert.h)の先頭の、'Fri Jun 30 21:44:43 JST 2017 Naoyuki Sawa'のコメントを参照して下さい。
#endif//__GNUC__
//}}2017/06/30変更:昨日(2017/06/29)、_Static_assertの定義を修正した影響で、P/ECE開発環境のGCCで警告が出るようになっていた問題に気付き、再度、修正しました。
//───────────────────────────────────────────────────────────────
//□参照資料「cppreference.com - static_assert」(http://en.cppreference.com/w/c/error/static_assert)
//│C > Error handling
//│static_assert
//│　Defined in header <assert.h>
//│　#define static_assert _Static_assert
//│　This convenience macro expands to the keyword _Static_assert
//│Example
//│　│#include <assert.h>
//│　│int main(void) {
//│　│　static_assert(2 + 2 == 4, "2+2 isn't 4"); //well-formed
//│　│　static_assert(sizeof(int) < sizeof(char), "this program requires that int is less than char"); //compile-time error
//│　│}
//│References
//│　・C11 standard (ISO/IEC 9899:2011):
//│　　・7.2/3 Diagnostics <assert.h> (p: 186)
//│See also
//│　「C++ documentation」(http://en.cppreference.com/w/cpp/language/static_assert) for Static Assertion
#define static_assert _Static_assert
//───────────────────────────────────────────────────────────────
//}}2016/10/23追加:_Static_assertとstatic_assertを追加しました。

//{{2017/06/29追加:「□static_assertの使用例」を追加しました。
//*****************************************************************************
//	□static_assertの使用例
//*****************************************************************************
#if 0
static_assert(1 < 2, "グローバルスコープで使用する例(true)");
static_assert(1 < 3, "グローバルスコープで使用する例(true)");		//★この行はエラーにならないのが正常ですが、2017/06/29以前は、VC++6.0/2017では問題無かったものの、GCCでは「redefinition of `__Static_assert__'」というエラーになってしまっていました(以下も同様です)。2017/06/29以降は、GCCでも問題無くなりました。
static_assert(1 > 2, "グローバルスコープで使用する例(false)");		//この行ではエラーが検出されるのが正常です。
static_assert(1 > 3, "グローバルスコープで使用する例(false)");		//この行ではエラーが検出されるのが正常です。
static void test() {
  static_assert(1 < 2, "関数スコープの先頭で使用する例(true)");
  static_assert(1 < 3, "関数スコープの先頭で使用する例(true)");
  static_assert(1 > 2, "関数スコープの先頭で使用する例(false)");	//この行ではエラーが検出されるのが正常です。
  static_assert(1 > 3, "関数スコープの先頭で使用する例(false)");	//この行ではエラーが検出されるのが正常です。
  puts("foo");
  {//C言語の場合は必要です。C++の場合は無くても構いません。
    static_assert(1 < 2, "ブロックスコープの先頭で使用する例(true)");
    static_assert(1 < 3, "ブロックスコープの先頭で使用する例(true)");
    static_assert(1 > 2, "ブロックスコープの先頭で使用する例(false)");	//この行ではエラーが検出されるのが正常です。
    static_assert(1 > 3, "ブロックスコープの先頭で使用する例(false)");	//この行ではエラーが検出されるのが正常です。
  }//C言語の場合は必要です。C++の場合は無くても構いません。
  puts("bar");
}
#endif
//}}2017/06/29追加:「□static_assertの使用例」を追加しました。

#ifdef  __cplusplus
}//extern "C"
#endif//__cplusplus

#endif/*_ASSERT_H*/
