public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Martin Sebor <msebor@gmail.com>
To: Iain Sandoe <iain@sandoe.co.uk>
Cc: Joseph Myers <joseph@codesourcery.com>,
	GCC Patches <GCC-patches@gcc.gnu.org>
Subject: Re: [PATCH v2] C-family : Add attribute 'unavailable'.
Date: Mon, 30 Nov 2020 10:04:49 -0700	[thread overview]
Message-ID: <fa3d3457-a28a-368b-15b1-65b02201db4e@gmail.com> (raw)
In-Reply-To: <EF078568-2A00-415A-90E0-C5F65EDFA450@sandoe.co.uk>

On 11/29/20 6:56 PM, Iain Sandoe wrote:
> Hi Martin,
> 
> Martin Sebor via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> 
>> On 11/10/20 12:38 PM, Iain Sandoe wrote:
> 
>>> —— commit message.
>>> If an interface is marked 'deprecated' then, presumably, at some 
>>> point it
>>> will be withdrawn and no longer available.  The 'unavailable' attribute
>>> makes it possible to mark up interfaces to indicate this status.
> 
>> Making an interface unavailable isn't the intent of deprecation in
>> standards like C, C++, or POSIX.  Rather, the intended next stage
>> after deprecation is to make the interface available for other uses,
>> either by the standards themselves, or by implementations, or by
>> programs (if its name is not in the reserved namespace).  So unless
>> you have other kinds of deprecation in mind this doesn't seem like
>> a fitting use case.
> 
> coming at things from the standards perspective .. perhaps.
> 
> .. however, in the first set of cases above, one never needs to indicate
>    unavailability  since the entity never becomes unavailable, it changes
>    meaning.
> 
> In practice, we don’t have markup of keywords etc. to indicate this (such
> deprecation has been handled specifically in the FEs).
> 
> The practical (and actual) use of these attributes is in describing the 
> lifecycle
> of system APIs.
> 
> In that context, one could see it being used to describe APIs withdrawn 
> in, say,
> a Posix standard (as implemented by a given system or according to specific
> compile-time flags).

Just for the sake of clarity, to make sure we are both talking about
the same thing, the term POSIX uses for "withdrawn" when referring
to APIs is removed.  Withdrawn is a term that ISO tends to apply to
whole standards.  For example, ISO 9945:2003 AKA SUSv3 is a withdrawn
revision of POSIX (likewise, C99 and C11 are withdrawn revisions of
C).

With that, the APIs that have been removed in recent POSIX versions
would not be appropriately described by the attribute, either on
paper, in the POSIX spec (if the hypothetical case when the attribute
was specified the C standard), or in implementations.  The APIs simply
don't exist and so are open to use by programs (unless they are in
the reserved namespace), or by implementations as extensions.
The latter typically means that the APIs are defined (i.e., can
continue to be linked to by legacy applications) but not declared
in the system's header so they can be defined by programs.  Declaring
removed APIs with the unavailable attribute would prevent that and so
would not be conforming.

An example from C (not yet POSIX) is the gets() function that was
removed in C11 (it's still SUSv4).  It's only declared in <stdio.h>
when targeting older versions of C and C++.  Because in more recent
versions of the standards gets is not a reserved name it's valid
for programs to declare symbols named gets (of any kind).  So
declaring gets in <stdio.h> with attribute unavailable would be
nonconforming.

My point here is not necessarily to object to the idea behind
the attribute but to draw attention to the fact that it's not
suitable for standard APIs.

>>> It is used
>>> quite extensively in some codebases where a single set of headers can 
>>> be used
>>> to permit code generation for multiple system versions.
>>
>> This sounds like a different use case than the next stage after
>> deprecation.  I haven't come across it but I imagine its purpose
>> is to foster portability between variants or flavors (rather
>> than versions) of APSs?  Say one set of APIs for a feature-rich
>> desktop variant of an OS versus a subset of the same APIs for
>> an embedded, more limited variant of the same OS.
> 
> In the case of Darwin, the compilers are capable of targeting multiple 
> versions
> of the system (one doesn’t need a separate GCC or clang to target each 
> version,
> there is a -mmacosx-version-min= flag that allows the target version to 
> be specified
> on the command line).
> 
> Rather than install many versions of headers (and libraries) for all the 
> system
> versions, the designers elected to have one copy with markup that 
> describes the
> availability of APIs.
> 
> the lifecycle is typically:
> 
> introduced from version P.Q (ergo, unavailable before that)
> perhaps deprecated at version R.S (ergo the user should be warned)
> withdrawn at version X.Y (and unavailable thereafter).
> 
> The headers contain macros that are expanded according to the version
> for which the code is being compiled - to produce deprecation warnings or
> unavailability errors if such APIs are *used* in the code.

I see.  That seems like a Darwin-specific use case, or one that may
be suitable for proprietary APIs not covered by the three language
standards (C, C++, or POSIX) where the attribute could only be used
this way as a non-conforming extension.  I suppose it might also be
applicable in the case of Linux distributions whose vendors support
multiple versions simultaneously, although I haven't come across
this use case.

> 
>>> From a configuration perspective, it also allows a compile test to 
>>> determine
>>> that an interface is missing - rather than requiring a link test.
>>> The implementation follows the pattern of attribute deprecated, but 
>>> produces
>>> an error (where deprecation produces a warning).
>>> This attribute has been implemented in clang for some years.
>>
>> The Clang manual says the attribute is useful in conjunction with
>> the enable_if and overloadble attributes in C, to remove overloads
>> of C functions from the overload set.  I'm trying to think how
>> the GCC implementation of the attribute might be useful in
>> the subset of cases that don't depend on the other two attributes
>> but I'm coming up empty (exceot for the different variants of
>> an API use case that seems rather esoteric).  It seems to me
>> the use case is close to #pragma GCC poison except more nunanced
>> (i.e., it doesn't poison a name but its uses in the given namespace,
>> as in functions, types, members, etc.)
> 
> Hopefully, the description above clarifies the intent.
> 
> It is possible, even likely, that the implementations in clang have 
> additional
> capabilities above those implemented in this first cut - and perhaps we 
> might
> adopt some of those in follow-on work.
> 
> however the immediate use-case is the hundreds of instances where APIs
> are marked up in the manner I’ve outlined above.
> 
>>> +@cindex @code{unavailable} function attribute
>>> +The @code{deprecated} attribute results in an error if the function
>>             ^^^^^^^^^^
>>
>> This should presumably read unavailable.
> 
> yes, good catch
> 
>>> +It is expected that items marked as @code{deprecated} will 
>>> eventually be
>>> +withdrawn from interfaces, and then become unavailable.  This attribute
>>> +allows for marking them appropriately.
>>
>> In Clang, declaring a member unavailable doesn't have the same effect
>> as withdrawing it (which I would interpret as removing).  The member
>> still takes up space, so if this patch does the same I think this
>> effect should be made clear here.
> 
> The intent is to match the behaviour of clang sufficiently closely that 
> GCC can
> make more effective use of the system headers on Darwin platforms (and, of
> course, allow for the same kind of life cycle markup on other platforms).
> 
>> Like attribute deprecated, I suspect attribute unavailable in GCC
>> will also be subject to the same catch 22 of marking up both a type
>> and its uses in APIs.  E.g., in:
>>
>>  struct __attribute__ ((deprecated)) A { ... };
>>
>>  struct B {
>>    // Clang accepts this w/o warning, GCC warns.
>>    struct A a __attribute__ ((deprecated));
>>    int i;
>>  };
>>
>> With unavailable, the problem will be made worse due to the error.
> 
> so this is a bug in GCC’s availability attributes (not specifically 
> caused by
> this patch) - addressing it for deprecation would naturally carry over 
> to the
> unavailable case.
> 
>> To be generally usable, I think GCC needs to change to behave more
>> like Clang.  As a motivating example, consider the deprecated POSIX
>> getitimer API:
>>
>>  struct itimerval { int it_interval, it_value; };
>>  int getitimer (int, struct itimerval*);
>>  int setitimer (int, const struct itimerval*, struct itimerval*);
>>
>> All three names are deprecated and so using each one alone outside
>> the header that declares them should trigger a deprecation message;
>> the declarations themselves must not.  If/when the APIs are removed,
>> marking them unavailable in the headers must likewise not trigger
>> errors.
> 
> Is there a PR for this ?
> (IMO it’s still a separate issue, curing the problem for deprecation 
> will also
>   cure it for unavailability).

There are a number of bugs for attribute deprecated.  The one that's
probably the closest to this problem is:
   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61754

It's been open since 2014.  Bugs about attributes don't tend to get
a lot of attention, either in GCC or within standards committees
(the standard form came to C from C++ where all attributes are
unspecified for templates).  Which is in part why I view with
skepticism enhancements built on top of the same poorly specified
foundation.

Martin

> 
> thanks for the review,
> Iain
> 
> 


  reply	other threads:[~2020-11-30 17:04 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <D12096AB-DAFD-4B69-B448-DAC32A851B40@sandoe.co.uk>
2020-11-10  7:54 ` [PATCH] " Richard Biener
2020-11-10 11:20   ` Iain Sandoe
2020-11-10 11:58     ` Richard Biener
2020-11-10 15:33 ` Joseph Myers
2020-11-10 19:38   ` [PATCH v2] " Iain Sandoe
2020-11-27 20:49     ` PING^1 " Iain Sandoe
2020-11-30 13:27       ` Nathan Sidwell
2020-11-29 23:00     ` Martin Sebor
2020-11-30  1:56       ` Iain Sandoe
2020-11-30 17:04         ` Martin Sebor [this message]
2020-12-01 21:07           ` Iain Sandoe
2020-12-21 19:58             ` Iain Sandoe
2021-01-04 20:19               ` Joseph Myers

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=fa3d3457-a28a-368b-15b1-65b02201db4e@gmail.com \
    --to=msebor@gmail.com \
    --cc=GCC-patches@gcc.gnu.org \
    --cc=iain@sandoe.co.uk \
    --cc=joseph@codesourcery.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).