とくにあぶなくないRiSKのブログ

危ないRiSKのブログだったかもしれない。本当はRiSKだけどググラビリティとか取得できるIDの都合でsscriskも使ったり。

g++ のバグ踏んだっぽい

また constexpr がらみなんですけどね。
constexpr な strcspn を実装してて,とあるテストコードで g++ のバグを踏んだっぽいです。
g++ のバージョンは最新版。

$ g++4.7 --version
g++.exe (GCC) 4.7.0 20110702 (experimental)
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

んで,再現コード

#include<cstddef>
#include<cassert>

inline constexpr const char* strchr(const char* s, int c)
{
 return *s == static_cast<char>(c) ? s
  : !*s ? nullptr
  : strchr(s + 1, c);
}

namespace detail{

 inline constexpr std::size_t strcspn_impl(char const * s1, char const * s2, std::size_t n)
 {
  return !*s1 || strchr(s2, *s1) ? n
   : strcspn_impl(s1 + 1, s2, n + 1);
 }

}

inline constexpr std::size_t strcspn(const char *s1, const char *s2)
{
 return detail::strcspn_impl(s1, s2, 0);
}

int main()
{
 static constexpr char a[]{"975"};
 constexpr std::size_t test1 = strcspn("0123456789", &a[0]); // OK.
 assert(test1 == 5);
 constexpr std::size_t test2 = strcspn("0123456789", a);     // Error. ハァ?
 assert(test2 == 5);
}

エラーメッセージはこんなの。

a.cpp: In function 'int main()':
a.cpp:31:55:   in constexpr expansion of 'strcspn(((const char*)"0123456789"), ((const char*)(& a)))'
a.cpp:23:39:   in constexpr expansion of 'detail::strcspn_impl(s1, s2, 0u)'
a.cpp:16:36:   in constexpr expansion of 'detail::strcspn_impl((s1 + 1u), s2, (n + 1u))'
a.cpp:16:36:   in constexpr expansion of 'detail::strcspn_impl((s1 + 1u), s2, (n + 1u))'
a.cpp:16:36:   in constexpr expansion of 'detail::strcspn_impl((s1 + 1u), s2, (n + 1u))'
a.cpp:16:36:   in constexpr expansion of 'detail::strcspn_impl((s1 + 1u), s2, (n + 1u))'
a.cpp:16:36:   in constexpr expansion of 'detail::strcspn_impl((s1 + 1u), s2, (n + 1u))'
a.cpp:31:55: error: '((((const char*)(& a)) + 2u) == 0u)' is not a constant expression

わけわからんエラーを吐きます。
配列から配列の先頭要素へのポインタへの(暗黙の)変換が絡むとバグが発動するみたいですね。って,前も同じ条件で発動するバグ踏んだよねぇ…。orz...