• 7.17.7.5 The atomic_fetch and modify generic functions and "address types"

    From Andrey Tarasevich@andreytarasevich@hotmail.com to comp.std.c on Fri Dec 27 14:06:33 2024
    From Newsgroup: comp.std.c

    7.17.7.5 says (https://port70.net/~nsz/c/c11/n1570.html#7.17.7.5)

    1 The following operations perform arithmetic and bitwise computations. All of these operations are applicable to an object of any atomic integer type. None of these operations is applicable to atomic_bool.

    If I understand it correctly, this wording is intended to restrict these operations to integers types only. I.e. they shall not be applied to
    atomic pointer types. Is that correct?

    Later 7.17.7.5 also says

    3 For address types, the result may be an undefined address, but the operations otherwise have no undefined behavior.

    However, I was unable to find any mention of "address types" anywhere in
    the standard. What types are "address types"?
    --
    Best regards,
    Andrey
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.std.c on Fri Dec 27 17:24:56 2024
    From Newsgroup: comp.std.c

    Andrey Tarasevich <andreytarasevich@hotmail.com> writes:
    7.17.7.5 says (https://port70.net/~nsz/c/c11/n1570.html#7.17.7.5)
    1 The following operations perform arithmetic and bitwise
    computations. All of these operations are applicable to an object of
    any atomic integer type. None of these operations is applicable to
    atomic_bool.

    If I understand it correctly, this wording is intended to restrict
    these operations to integers types only. I.e. they shall not be
    applied to atomic pointer types. Is that correct?

    Later 7.17.7.5 also says

    3 For address types, the result may be an undefined address, but the
    operations otherwise have no undefined behavior.

    However, I was unable to find any mention of "address types" anywhere
    in the standard. What types are "address types"?

    I think you've found an error in the standard. It also appears in
    the C17 and the N3096 and N3301 drafts.

    There are no other occurrences of "address type" in the standard.
    Presumably it was meant to be "pointer type", but pointer types
    are already excluded.

    An aside: The wording that excludes _Atomic bool is improved
    in N3096:

    The following operations perform arithmetic and bitwise
    computations. All these operations are applicable to an object
    of any atomic integer type other than _Atomic bool or the atomic
    version of an enumeration with underlying type bool.
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.std.c on Wed Jan 1 20:31:18 2025
    From Newsgroup: comp.std.c

    Andrey Tarasevich <andreytarasevich@hotmail.com> writes:

    7.17.7.5 says (https://port70.net/~nsz/c/c11/n1570.html#7.17.7.5)

    1 The following operations perform arithmetic and bitwise
    computations. All of these operations are applicable to an object of
    any atomic integer type. None of these operations is applicable to
    atomic_bool.

    If I understand it correctly, this wording is intended to restrict
    these operations to integers types only. I.e. they shall not be
    applied to atomic pointer types. Is that correct?

    I believe the intent is that the atomic_fetch_key() family of
    functions may be called with either atomic integer types or atomic
    pointer types (with the possible exception of atomic boolean types).

    If the committee had meant to rule out atomic pointer types, the
    standard could have given an explicit statement to that effect, like
    what was done for atomic boolean types. The standard does not
    include any explicit statement ruling out the use of atomic pointer
    types; if anything atomic pointer types are implicitly included by
    the parameter type name A, which is described in 7.17.1 paragraph 5
    (paragraph 6 in some later versions of the standard).

    Similarly, if the committee had meant to rule out atomic pointer
    types, there is no reason for the last sentence in paragraph 3,
    talking about what behaviors are allowed when address types are
    used. Presumably the phrase "address types" is meant to be the same
    as "pointer types" (see also below), which seems like the only
    plausible interpretation.

    There is no reason to think the inclusion of the last sentence of
    paragraph 3 is an oversight. This sentence has survived unchanged
    for more than 14 years, going back to at least 2010. But other
    parts of section 7.17 were changed significantly during that time;
    hence it seems unlikely that such an important incongruity was
    missed over all of that time.

    Why then does the standard take the trouble to say that these
    operations are applicable to atomic integer types? I think the
    confusion comes from reading "applicable" as "allowed". A more
    consistent reading is for "applicable" to mean "well-defined". All
    of the atomic_fetch_key() family of functions are well-defined for
    all inputs of atomic integer type, even going so far as to stipulate
    two's complement with wraparound for signed types (and this at a
    time when the C standard did not require two's complement for signed
    integer types generally). Atomic pointer types do not have this
    property of producing well-defined results. Indeed, there is a
    limited degree of undefined behavior that may result. In that sense
    the operations of atomic_fetch_key() are not fully applicable to
    atomic pointer types. But not applicable does not mean disallowed.


    Later 7.17.7.5 also says

    3 For address types, the result may be an undefined address, but the
    operations otherwise have no undefined behavior.

    However, I was unable to find any mention of "address types" anywhere
    in the standard. What types are "address types"?

    The phrase "address types" is a holdover from earlier drafts of the
    C standard. It's instructive to compare N1547, a draft from
    December 2010, to N1570, a draft from April 2011. The phrase
    "address types" is used in several places, including to describe a
    type name "atomic_address" (a struct type). I won't go through all
    of the differences, which are fairly widespread. But looking them
    over is I think convincing that pointer types were left in
    deliberately.

    A point that needs clarifying is whether bitwise operations are
    allowed for atomic pointer type. The bitwise operations are allowed
    by gcc, and disallowed by clang. I think an argument can be made
    either way. Personally I think allowing bitwise operations is more
    compelling than disallowing them, but I have to acknowledge the
    possibility that the intent was place them off limits (meaning,
    requiring a diagnostic). That said, I don't see any explicit text
    in the standard that forces that conclusion.

    Minor point: it is possible the gcc behavior a producing a '1'
    difference in the example program posted in comp.lang.c is a
    holdover from interpreting an earlier draft of the C standard, and
    then not changing it after the actual standard was ratified. I
    continue to think that what gcc did was wrong and what clang did was
    right. If someone thinks otherwise I'd be interested to hear
    whatever reasoning underlies their other position.

    Disclaimer: my research was confined to looking at several drafts
    of the C standard. I didn't make any effort to find or read DRs
    that might be relevant, or any meeting notes or other official
    documents that discuss or mention the issue.
    --- Synchronet 3.20a-Linux NewsLink 1.114