Description
This bug exists in all released clang versions with C++20 support up to trunk.
The following code defined classes Publ
/Priv
/Prot
with different visibility of member x
, and inherit into a templated class D
specialized by its accessibility using C++20 concept.
Boolean var has
shows the specialization route.
In theory, only public member is visible, while protected/private are not.
These are checked by static_assert
.
Clang mistakenly thinks protected member from class Prot
is accessible, and failed to compile this code at the last static_assert, while any versions of gcc and msvc works.
Even more confusing, if we do the exact same thing again, with another class Same
identical to Prot
, but query the concept directly before template instantiation, clang will give opposite answer.
template<typename T> concept has_x = requires(T t){{ t.x };};
class Publ { public: int x = 0; };
class Priv { private: int x = 0; };
class Prot { protected: int x = 0; };
class Same { protected: int x = 0; };
template<typename T> class D;
template<typename T> requires ( has_x<T>) class D<T>: public T { public: static constexpr bool has = 1; };
template<typename T> requires (!has_x<T>) class D<T>: public T { public: static constexpr bool has = 0; };
// "Same" is identical to "Prot" but queried before used.
static_assert(!has_x<Same>, "Protected should be invisible.");
static_assert(!D<Same>::has, "Protected should be invisible.");
static_assert( D<Publ>::has, "Public should be visible.");
static_assert(!D<Priv>::has, "Private should be invisible.");
static_assert(!D<Prot>::has, "Protected should be invisible."); // clang failed here.
int main() { return 0; }
- GCC 14.2 works.
- clang 19.1.0 failed.
- MSVC 19.40 x64 works.
- clang-cl 18.1.0 failed.