invalid use of incomplete type

C++ のプログラムを書いていて、 GCC (5.3.0) ではエラーが報告されるのに Clang では警告すらなくコンパイルできた場合を見付けた。 Watcom C++ や Visual C++ でもコンパイルできるので GCC のバグだろうか? それとも未定義の挙動だろうか?

具体的には以下のコードである。

template<class T>
class foo {
  friend void T::qux(void);
private:
  int baz;
public:
  foo(void) : baz(1){}
};

#include <iostream>

class bar {
public:
  void qux(void) {
    std::cout << data.baz << std::endl;
  }
private:
  foo<bar> data;
};

int main(void) {
  bar x;
  x.qux();
  return 0;
}

エラーの内容は以下のようなものであった。

prog.cc: In instantiation of 'class foo<bar>':
prog.cc:18:12:   required from here
prog.cc:3:15: error: invalid use of incomplete type 'class bar'
   friend void T::qux(void);
               ^
prog.cc:12:7: note: forward declaration of 'class bar'
 class bar {
       ^~~
prog.cc: In member function 'void bar::qux()':
prog.cc:15:23: error: 'int foo<bar>::baz' is private within this context
     std::cout << data.baz << std::endl;
                       ^~~
prog.cc:5:7: note: declared private here
   int baz;
       ^~~

テンプレート引数で与えられた型がこの時点で不完全なのは当たり前のことで、テンプレートっていうのはそういうものだろうと思っていたので、今更それでエラーにされてもなぁという気持ちになる。

Document ID: 816fe8b9c9d96d8c1a313f5a3091702e