Document Number:
N2209
Submitter:
Martin Sebor
Submission Date:
March 26, 2018
Subject:
Atomic Pointers In Expressions
Summary
The current specification makes it a constraint violation to use
pointers to objects of atomic types in certain contexts where they
can, and in our view should be permitted. The following paragraphs
detail the restriction and the contexts in which it applies.
In §6.2.5 Types, paragraph 27 reads:
Further, there is the _Atomic qualifier. The presence of
the _Atomic qualifier designates an atomic type. The size,
representation, and alignment of an atomic type need not be the same as
those of the corresponding unqualified type. Therefore, this Standard
explicitly uses the phrase "atomic, qualified or unqualified type"
whenever the atomic version of a type is permitted along with the other
qualified versions of a type. The phrase "qualified or unqualified type",
without specific mention of atomic, does not include the atomic types.
The only occurrences of the phrase "atomic, qualified or unqualified
type" in § 6.5 Expressions are in the following subsections:
-
§6.5.2.3 Structure and union members,
-
§6.5.2.4 Postfix increment and decrement operators,
-
§6.5.3.1 Prefix increment and decrement operators,
-
§6.5.4 Cast operators,
-
§6.5.16.1 Simple assignment — as the left operand,
- §6.5.16.2 Compund assignment — also as the left.
operand
Of the remaining contexts, the following expressions specify among
their constraints that one or both pointer operands shall be "qualified
or unqualified" versions of a type without mentioning atomic types:
-
§6.5.6 Additive operators,
-
§6.5.8 Relational operators,
-
§6.5.9 Equality operators,
-
§6.5.15 Conditional operators,
-
§6.5.16.1 Simple assignment — as the right operand.
Consequently, pointers to objects of atomic types are not valid
operands in the expressions above. We believe these constraints are
both unnecessary and unintended. For example, there is no reason for
the following code to be rejected:
extern _Atomic int a[2], *p;
a[0] = a == p ? a[1] : a[0];
No implementation is known to enforce the constraint in these contexts.
The Simple assignment constraints are worth discussing in more detail.
The relevant constraints are as follows:
One of the following shall hold:112)
…
— the left operand has atomic, qualified, or unqualified pointer
type, and (considering the type the left operand would have after lvalue
conversion) both operands are pointers to qualified or unqualified
versions of compatible types, and the type pointed to by the left has
all the qualifiers of the type pointed to by the right;
— the left operand has atomic, qualified, or unqualified pointer
type, and (considering the type the left operand would have after lvalue
conversion) one operand is a pointer to an object type, and the other is
a pointer to a qualified or unqualified version of void, and
the type pointed to by the left has all the qualifiers of the type
pointed to by the right;
…
Atomic-qualified void types are permitted in paragraph 3
of §6.7.3 Type qualifiers:
The type modified by the _Atomic qualifier shall not be
an array type or a function type.
A strict (perhaps pedantic?) reading of the constraints implies that
although it is valid to assign an unqualified pointer to an
atomic-qualified pointer object it is a constraint violation to assign
an _Atomic pointer to an object of a compatible pointer type
because the qualifiers allowed for the right operand do not include
_Atomic (pursuant to §6.2.5 Types, paragraph 27
the phrase "qualified or unqualified type", without specific mention
of atomic, does not include the atomic types). By way of
an example:
extern T *p;
_Atomic T *ap, *aq;
ap = p; // unsafe but valid
aq = ap; // safe but constraint violation
The first assignment is unsafe because (unlike with other qualifiers)
accessing a non-atomic object using an lvalue of an atomic-qualified
type doesn't have defined semantics.
The above is so regardless of the type T. Provided
atomic-qualified void pointers are intended to be allowed
(not all implementations that support atomics accept them), this also
affects the second bullet. Otherwise, if atomic-qualified void
pointers are not intended to be permitted then only the fisrst bullet
is affected. In that case, however, paragraph 3 of
§6.7.3 Type qualifiers needs to be adjusted to exclude
void from the set of types that may not be modified by
the _Atomic qualifier.
Proposed Resolution
We propose to allow pointers to objects of atomic types in the contexts
above. Specifically, we propose to make the following changes.
In §6.5.6 Additive operators make changes in paragraph 3
as indicated below.
For subtraction, one of the following shall hold:
— both operands have arithmetic type;
— both operands are pointers to atomic, qualified
or unqualified versions of compatible complete object types; or
— the left operand is a pointer to a complete object type and
the right operand has integer type.
In §6.5.8 Relational operators make changes in paragraph 2
as indicated below.
One of the following shall hold:
— both operands have real type; or
— both operands are pointers to atomic, qualified
or unqualified versions of compatible object types.
In §6.5.9 Equality operators make changes in paragraph 2
as indicated below.
One of the following shall hold:
— both operands have arithmetic type;
— both operands are pointers to atomic, qualified
or unqualified versions of compatible types;
…
In §6.5.15 Conditional operator make changes in paragraph 3
as indicated below.
One of the following shall hold for the second and third operands:
…
— both operands are pointers to atomic, qualified
or unqualified versions of compatible types;
— one operand is a pointer and the other is a null pointer constant;
or
— one operand is a pointer to an object type and the other is
a pointer to a qualified or unqualified version of void.
In §6.5.16.1 Simple assignment make changes in paragraph 1
as indicated below.
One of the following shall hold:112)
…
— the left operand has atomic, qualified, or unqualified pointer
type, and (considering the type the left operand would have after lvalue
conversion) both operands are pointers to atomic, qualified
or unqualified versions of compatible types, and the type pointed to by
the left has all the qualifiers of the type pointed to by the right
,and either both operands have an atomic-qualified pointer type
or neither does;
— the left operand has atomic, qualified, or unqualified pointer
type, and (considering the type the left operand would have after lvalue
conversion) one operand is a pointer to an object type, and the other is
a pointer to an atomic, qualified or unqualified version of
void, and the type pointed to by the left has all the qualifiers
of the type pointed to by the right, and either both operands have
an atomic-qualified pointer type or neither does;
…