Consider the following code: template<typename T> struct S { static constexpr int bar = T::foo; }; struct U: S<U> { static constexpr int foo = 42; }; int main() { } GCC compiles it, but it shouldn't. The type T is not a complete type when bar is initialized. Here is a discussion on stackoverflow where reasons are discussed: http://stackoverflow.com/questions/37816186/initializing-a-static-constexpr-data-member-of-the-base-class-by-using-a-static Link to the standard (working draft) are provided as well in the discussion. Other compilers (mostly clang) correctly reject it.
We have been interpreting the relevant text in temp.inst, p1 that: "The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions, [...] static data members [...]; and it causes the implicit instantiation of the definitions of unscoped member enumerations and member anonymous unions." to mean that the only the declaration but not the initializer of the static const data member declared in a class is instantiated, and resolving other bug reports like this one as invalid (for example, bug 58848 and bug 70820). But the interpretation in the stackoverflow response that the initializer expression for a static const data member initialized in the class is actually part of the declaration does seem to be supported by the text in class.static.data, p3 (quoted below) and by two other implementations I tried (Clang 3.8 and EDG eccp 4.11): "A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [...] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer." I CC Jason for his opinion.
The fact that it compiles it is misleading at least. Consider the following code: #include<type_traits> template<typename...> using void_t = void; template<typename, typename = void_t<>> struct has_foo: std::false_type { }; template<typename T> struct has_foo<T, decltype(T::foo)>: std::true_type { }; struct S: has_foo<S> { static constexpr int foo = 42; }; int main() { // S does not have foo... static_assert(not S::value, "!"); // ... really? static_assert(S::foo == 42, "!"); } The result is unexpected indeed. So subtle an issue to find, that one.
Following the adoption of P0386R2 into the working draft, the declaration of bar is now a definition, because bar is an inline variable. This makes GCC's behaviour standard-conforming in C++1z mode as far as I can tell. However, I think a fix should still be applied to C++14 and 11 modes, in the interest of portability.
Confirmed.