[PATCH] diagnose specializations of deprecated templates (PR c++/84318)

Jason Merrill jason@redhat.com
Tue Feb 13 20:09:00 GMT 2018


On Tue, Feb 13, 2018 at 2:59 PM, Martin Sebor <msebor@gmail.com> wrote:
> On 02/13/2018 12:15 PM, Jason Merrill wrote:
>> On Tue, Feb 13, 2018 at 1:31 PM, Martin Sebor <msebor@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 <msebor@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
>



More information about the Gcc-patches mailing list