On Tue, Feb 13, 2018 at 2:59 PM, Martin Sebor <mse...@gmail.com> wrote: > On 02/13/2018 12:15 PM, Jason Merrill wrote: >> On Tue, Feb 13, 2018 at 1:31 PM, Martin Sebor <mse...@gmail.com> wrote: >>> On 02/13/2018 09:24 AM, Martin Sebor wrote: >>>> >>>> >>>> On 02/13/2018 08:35 AM, Martin Sebor wrote: >>>>> >>>>> >>>>> On 02/13/2018 07:40 AM, Jason Merrill wrote: >>>>>> >>>>>> >>>>>> On Mon, Feb 12, 2018 at 6:32 PM, Martin Sebor <mse...@gmail.com> >>>>>> wrote: >>>>>>> >>>>>>> >>>>>>> While testing my fix for 83871 (handling attributes on explicit >>>>>>> specializations) I noticed another old regression: while GCC 4.4 >>>>>>> would diagnose declarations of explicit specializations of all >>>>>>> primary templates declared deprecated, GCC 4.5 and later only >>>>>>> diagnose declarations of explicit specializations of class >>>>>>> templates but not those of function or variable templates. >>>>>> >>>>>> >>>>>> >>>>>> Hmm, the discussion on the core reflector seemed to be agreeing that >>>>>> we want to be able to define non-deprecated specializations of a >>>>>> deprecated primary template. >>>>> >>>>> >>>>> >>>>> Yes, that's what Richard wanted to do. The only way to do it >>>>> within the existing constraints(*) is to define a non-deprecated >>>>> primary, and a deprecated partial specialization. This is in line >>>>> with that approach and supported by Clang and all other compilers >>>>> I tested (including Clang). >>>> >>>> >>>> >>>> To clarify, this approach works for class templates (e.g., like >>>> std::numeric_limits that was mentioned in the core discussion) >>>> and for variable templates. Functions have no partial >>>> specilizations so they have to be overloaded to achieve the same >>>> effect. >>>> >>>> Implementations don't treat the deprecated attribute on partial >>>> specializations consistently. >>>> >>>> EDG accepts and honors it on class template partial specializations >>>> but rejects it with an error on those of variables. >>>> >>>> Clang accepts but silently ignores it on class template partial >>>> specializations and rejects with an error it on variables. >>>> >>>> MSVC accepts and honors it on variables but silently ignores it >>>> on class template partial specializations. >>>> >>>> GCC ignores it silently on class partial specializations and >>>> with a warning on variables (I opened bug 84347 to track this >>>> and to have GCC honor is everywhere). >>>> >>>> This is clearly a mess, which isn't surprising given how poorly >>>> specified this is in the standard. But from the test cases and >>>> from the core discussion it seems clear that deprecating >>>> a template, including its partial specializations (as opposed >>>> to just a single explicit specialization) is desirable and >>>> already supported, and that the wording in the standard just >>>> needs to be adjusted to reflect that. >>>> >>>>> >>>>> Martin >>>>> >>>>> [*] Except (as Richard noted) that the standard doesn't seem to >>>>> allow a template to be deprecated. I think that's a bug in the >>>>> spec because all implementations allow it to some degree. >>> >>> >>> >>> One other note. While thinking about this problem during >>> the core discussion, another approach to deprecating a primary >>> template without also deprecating all of its specializations >>> occurred to me. >>> >>> 1) First declare the primary template without [[deprecated]]. >>> 2) Next declare its non-deprecated specializations (partial >>> or explicit). >>> 3) Finally declare the primary again, this time [[deprecated]]. >>> >>> Like this: >>> >>> template <class T> struct S; >>> template <class T> struct S<const T> { }; >>> template <class T> struct [[deprecated]] S<volatile T> { }; >>> template <class T> struct [[deprecated]] S { }; >>> >>> S<int> si; // warning >>> S<const int> sci; // no warning >>> S<volatile int> svi; // warning >>> >>> This works as expected with Intel ICC. All other compilers >>> diagnose all three variables. I'd say for [[deprecated]] it >>> should work the way ICC does. (For [[noreturn]] the first >>> declaration must be [[noreturn]], so there this solution >>> wouldn't work also because of that, in addition to function >>> templates not being partially-specializable.) >> >> >> My understanding of the reflector discussion, and Richard's comment in >> particular, was that [[deprecated]] should apply to the instances, not >> the template itself, so that declaring the primary template >> [[deprecated]] doesn't affect explicit specializations. Your last >> example should work as you expect in this model, but you can also >> write the simpler >> >> template <class T> struct [[deprecated]] S { }; >> template <class T> struct S<const T> { }; // no warning > > > With this approach there would be no way to deprecate all of > a template's specializations) because it would always be > possible for a user to get around deprecation by defining > their own specialization, partial or explicit.
Yep. And so he suggested that we might want to add a new way to write attributes that do apply to the template name. > I think we need to give users the choice of being able to do > one without the other (in addition to both). I.e., either of > > 1) Deprecate a primary and all its uses (including partial and > explicit specializations). > > 2) Deprecate just a subset of specializations of a template > without also deprecating the rest. > > An example of (1) is std::auto_ptr or the std::is_literal_type > type trait. The intent is to remove them from namespace std > someday and providing any specializations for them will then > become an error. > > An example of (2) is the std::numeric_limits primary template > that Richard brought up. That was my understanding of what > he wanted to do but even if that's not what he meant it's > a reasonable use case as well. > > Martin >