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; }
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.
```cc
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.
- https://godbolt.org/z/Pb9j5x3q8
- clang 19.1.0 failed.
- https://godbolt.org/z/3E9qnxKbW
- MSVC 19.40 x64 works.
- https://godbolt.org/z/Tf14M4dK4
- clang-cl 18.1.0 failed.
- https://godbolt.org/z/rjPoE1ve9
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 memberx
, and inherit into a templated classD
specialized by its accessibility using C++20 concept. Boolean varhas
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 toProt
, but query the concept directly before template instantiation, clang will give opposite answer.