C++コンパイラ GCCとClangからのメッセージをお読みください

5,501 views
5,273 views

Published on

Published in: Technology
0 Comments
5 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
5,501
On SlideShare
0
From Embeds
0
Number of Embeds
53
Actions
Shares
0
Downloads
19
Comments
0
Likes
5
Embeds 0
No embeds

No notes for slide

C++コンパイラ GCCとClangからのメッセージをお読みください

  1. 1. C++コンパイラ GCCとClangからのメッセージをお読みください
  2. 2. お詫びとおことわり● うっかり自宅のclangにアクセスできなくして しまったので、一部のサンプルコード(のエ ラーメッセージ)を掲載できなくなってしまい ました。● なので実感のつかみにくいかもしれませんがご 了承ください。
  3. 3. GCCのエラーといえば /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h: In function ‘void std::sort(_RAIter, _RAIter) [with _RAIter = std::_List_iterator<int>]’: prog.cpp:6: instantiated from here /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:4783: error: no match for ‘operator-’ in ‘__last - __first’ /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h: In function ‘void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = std::_List_iterator<int>]’: /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:4785: instantiated#include <list> from ‘void std::sort(_RAIter, _RAIter) [with _RAIter = std::_List_iterator<int>]’ prog.cpp:6: instantiated from here#include <algorithm> /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1827: error: no match for ‘operator-’ in ‘__last - __first’ /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1829: error: no match for ‘operator+’ in ‘__first + 16’int main() { /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1830: error: no match for ‘operator+’ in ‘__first + 16’ std::list<int> l; /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h: In function ‘void std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = std::_List_iterator<int>]’: std::sort(l.begin(), /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1833: instantiated from ‘void std::__final_insertion_sort(_RandomAccessIterator, l.end()); _RandomAccessIterator) [with _RandomAccessIterator = std::_List_iterator<int>]’ /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:4785: instantiated} from ‘void std::sort(_RAIter, _RAIter) [with _RAIter = std::_List_iterator<int>]’ prog.cpp:6: instantiated from here /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1753: error: no match for ‘operator+’ in ‘__first + 1’ /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1833: instantiated from ‘void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = std::_List_iterator<int>]’ /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:4785: instantiated from ‘void std::sort(_RAIter, _RAIter) [with _RAIter = std::_List_iterator<int>]’ prog.cpp:6: instantiated from here /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1759: error: no match for ‘operator+’ in ‘__i + 1’ !!!非常に明解で分かりやすい!!!
  4. 4. 熟練の暗号解読班の定石手段● エラーメッセージから “instantiated from here” を探す● そこからエラーメッセージを逆に辿りながら、 実体化された型や関数呼び出しをドキュメント と照合する ● テンプレート引数は要件を満たしているか ● 実体化されたテンプレートの定義は意図したものか
  5. 5. 熟練の暗号解読班の定石手段● boost::mpl::eval_if<boost::mpl::apply<boost ::remove_reference<boost::mpl::placeholders ::…… ● perl -ple s/(?:w+::)*//g● boost::fusion::vector<hoge, fuga, piyo, void_, void_, void_, void_, void_, void_, void_, …… ● perl -ple s/,void_//g;● STLfilt
  6. 6. 一方新兵はClangを使った● ヴィジュアルで位置を指摘してくれる! /usr/include/c++/4.3/bits/stl_algo.h:4784:22: error: invalid operands to binary expression (std::_List_iterator<int> and std::_List_iterator<int>) std::__lg(__last - __first) * 2); ~~~~~~ ^ ~~~~~~~● マクロ展開後のコードのエラーならそれも追っ てくれる! for FOO(1); f /tmp/webcompile/_20978_0.cc:6:5: error: no matching function call to ^~~ ● void f() {} /tmp/webcompile/_20978_0.cc:2:13: note: instantiated from: #define FOO BAR #define FOO BAR ^ #define BAR f /tmp/webcompile/_20978_0.cc:3:13: note: instantiated from: #define BAR f int main() { ^ FOO(1); /tmp/webcompile/_20978_0.cc:1:6: note: candidate function not } viable: requires 0 arguments, but 1 was provided void f() {} ^ 1 error generated. Clang大勝利!!!
  7. 7. ところがnamespace ns { struct z {}; template<typename T> struct s {}; template<typename T> auto f(s<T> x) -> decltype(f(T())) { return f(T()); } template<typename T> struct a { static_assert(sizeof(T) && false, "failed"); }; template<typename T = int> auto f(z x) -> decltype(a<T>(), 1) { return 0; } s<s<s<z> > > three;}int main() { これを現行のClangとGCCでコンパイルすると f(ns::three);} f(ns::three); の関数呼びだしを解決できなかった という旨のメッセージを吐く
  8. 8. ところが● 先のコードは、再帰的な実体化を試みた末auto f(z)-> decltype(a<T>, 0)の実体化に失敗するのが原因 ● f(ns::three)の呼び出し解決するためにauto f(s<s<z> >)を実体化しよ うとする。 ● 戻り値の型を求めるためにf(T())の呼び出し解決をしようとする – その呼び出しを解決するためにf(s<z>)を(ry ● その解決のためにf(z)を解決しようとして、失敗する – f(T())の呼び出し解決に失敗する ● f(T())の(ry ● f(ns::three)の呼び出し解決に失敗する ● f(ns::three)の呼び出しがエラーとなる
  9. 9. ところが● 先のコードは、再帰的な実体化を試みた末auto f(z)-> decltype(a<T>, 0)の実体化に失敗するのが原因 ● f(ns::three)の呼び出し解決するためにauto f(s<s<z> >)を実体化しよ うとする。 ● 戻り値の型を求めるためにf(T())の呼び出し解決をしようとする – その呼び出しを解決するためにf(s<z>)を(ry ● その解決のためにf(z)を解決しようとして、失敗する – f(T())の呼び出し解決に失敗する ● f(T())の(ry ● f(ns::three)の呼び出し解決に失敗する ● f(ns::three)の呼び出しがエラーとなる
  10. 10. 老兵再び● Clangには呼び出し解決に失敗した場合、各呼び 出し候補について、その候補が選ばれなかった 理由を表示する機能がある。● GCC4.7にも同様の機能が付いたが、こちらはあ る候補の選択されなかった理由が「関数の呼び 出し解決失敗」である場合、その呼び出しの候 補と失敗理由についても再帰的に表示してくれ る GCC(>=4.7)大勝利!!!
  11. 11. まとめ● 両方でコンパイルできるようにコードを書い て、適切に使い分けましょう
  12. 12. 問題● ドキュメントがない部分(内部実装など)を通る と、どの実体化でおかしくなったのか判別する ことが困難 ● See: PStade.Oven

×