C++14で連立方程式をコンパイル時に解くコードを書いていた時に、偶然コンパイラの奇妙な振る舞いを見つけた。
最終的に、そのコードは以下のようなところにまで還元された。
prog.cc
#include <iostream>
constexpr int foo(){
for(int i = 0; i < 1; i++){
if(i == 0) continue;
for(int j = 0; j < 1; j++);
}
return 334;
}
int main(){
constexpr int a = foo();
std::cout << a << "\n";
return 0;
}
foo()は2重ループとcontinue文を含んでいるが、実際には常に334を返すだけのconstexprな関数だ。
それを使ってconstexpr int a = foo();
と宣言することにより、aの値はコンパイルの時点で334に確定する。...はずだった。
実際clangや6.2.0までのgccでこれは正しくコンパイルできる。
ところが、gcc 7.0.1では
prog.cc: In function 'int main()':
prog.cc:12:26: in constexpr expansion of 'foo()'
prog.cc:6:9: error: constexpr loop iteration count exceeds limit of 262144 (use -fconstexpr-loop-limit= to increase the limit)
for(int j = 0; j < 1; j++);
^~~
というコンパイルエラーが出てしまい、またgcc 6.3.0に至っては何も言わずに黙り込んでしまう。なぜかfoo()内のループが無限ループ化してしまっているようだ。
ちなみにこのfoo()内のif(i == 0) continue;
かfor(int j = 0; j < 1; j++);
のどちらかを取り除くとgcc 6.3.0, gcc 7.0.1でもうまくコンパイルでき、またmain()内のaのconstexprを取り除いてもうまくいく。
おそらくgccのバグだと思う。近いうちに報告してみようか...?