On Wed, 15 Jul 2026 at 16:02, Jakub Jelinek <[email protected]> wrote:
>
> On Wed, Jul 15, 2026 at 03:47:55PM +0100, Jonathan Wakely wrote:
> > > --- libstdc++-v3/include/bits/c++config.jj 2026-01-02 22:41:17.624547836
> > > +0100
> > > +++ libstdc++-v3/include/bits/c++config 2026-07-15 12:24:00.321648893
> > > +0200
> > > @@ -927,6 +927,14 @@ namespace __gnu_cxx
> > > # define _GLIBCXX_USE_BUILTIN_TRAIT(BT) 0
> > > #endif
> > >
> > > +#if __has_cpp_attribute(_Clang::__no_specializations__)
> > > +# define _GLIBCXX_NO_SPECIALIZATIONS(T) \
> > > + [[_Clang::__no_specializations__ ("explicit or partial specialization
> > > of " \
> > > + #T)]]
> > > +#else
> > > +# define _GLIBCXX_NO_SPECIALIZATIONS(T)
> > > +#endif
> >
> > I wonder if we should do:
> >
> > #if __has_cpp_attribute(_Clang::__no_specializations__)
> > # define _GLIBCXX_NO_SPECIALIZATIONS(T) \
> > [[_Clang::__no_specializations__ ("explicit or partial specialization of
> > std::" \
> > #T)]] T
> > #else
> > # define _GLIBCXX_NO_SPECIALIZATIONS(T) T
> > #endif
> >
> > And then we would not have to repeat the type:
> >
> > class _GLIBCXX_NO_SPECIALIZATIONS(tuple) {
> >
> > But that's minor and could be changed later.
>
> Up to you. One thing is leaving out the std::, i.e. implying we only use
> the macro on std:: namespace templates and not std::something:: etc.
There are not as many types in nested namespaces and currently none
that need this rule. And if we do need to use this on one we could
define another macro where the namespace is a macro argument.
> And the other thing is the inclusion of T in there. Wonder if that won't
> upset doxygen or if users reading the sources won't be confused by that.
Doxygen can be told what _GLIBCXX_NO_SPECIALIZATIONS(x) expands to (in
fact we need to do that because even your current patch will confused
Doxygen).
But now that I look at the output from GCC and Clang, I'm not sure we
even need the string literal. It's repeating what the compiler says
anyway:
GCC says:
spec.cc:12:19: error: 'struct std::tuple<>' cannot be specialized:
'explicit or partial specialization of std::tuple'
[-Winvalid-specialization]
12 | template<> struct tuple<> { };
| ^~~~~~~
spec.cc:10:70: note: declared 'clang::no_specializations' here
10 | template<typename...> struct
_GLIBCXX_NO_SPECIALIZATIONS(std::tuple) tuple { };
|
^~~~~
And Clang says:
spec.cc:12:19: error: 'tuple' cannot be specialized: explicit or
partial specialization of std::tuple [-Winvalid-specialization]
12 | template<> struct tuple<> { };
| ^
spec.cc:10:30: note: marked '_Clang::no_specializations' here
10 | template<typename...> struct
_GLIBCXX_NO_SPECIALIZATIONS(std::tuple) tuple { };
| ^
spec.cc:3:5: note: expanded from macro '_GLIBCXX_NO_SPECIALIZATIONS'
3 | [[_Clang::__no_specializations__("explicit or partial
specialization of " #T)]]
| ^
1 error generated.
In both cases, the compiler already says that the template cannot be
specialized. GCC names it more clearly, as 'struct std::tuple<>'
rather than just 'tuple'.
So we could just use an object-like macro instead of a function-like macro:
template<typename...> struct _GLIBCXX_NO_SPECIALIZATIONS tuple {
> > > @@ -1942,6 +1946,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > > tuple(allocator_arg_t, _Alloc, tuple<_UTypes...>) ->
> > > tuple<_UTypes...>;
> > > #endif
> > >
> > > +#pragma GCC diagnostic push
> > > +#pragma GCC diagnostic ignored "-Winvalid-specialization"
> >
> > Does this need '#pragma clang diagnostic' as well?
>
> Apparently not needed.
> https://godbolt.org/z/WhTEcM6Yr
> seems all of clang 20, 21, 22 and trunk handle it,
> template <typename T>
> struct [[clang::no_specializations]] S {};
> #pragma GCC diagnostic push
> #pragma GCC diagnostic ignored "-Winvalid-specialization"
> template <>
> struct S <int> {};
> #pragma GCC diagnostic pop
> template <>
> struct S <long> {};
> error on S <long> specialization and are quiet on S <int>.
> And clang 19 and older doesn't support _Clang::__no_specializations__.
>
> If you want, perhaps the
> #pragma GCC diagnostic push
> #pragma GCC diagnostic ignored "-Winvalid-specialization"
> and
> #pragma GCC diagnostic pop
> lines could be wrapped with
> #if __has_cpp_attribute (_Clang::__no_specializations__)
> ...
> #endif
> so that older clang++ doesn't emit there -Wunknown-warning-option
> warning with -Wsystem-headers.
If Clang 20 and later are happy with it, then that's good enough. By
the time GCC 17 is released they'll be on Clang 24.