So I was re-reading C17 6.5/6 - 6.5/7 regarding effective type and strict aliasing, but couldn't figure out how to treat qualifiers. Some things confuse me:
I always assumed that qualifiers aren't really relevant for effective type since the rules speak of lvalue access, meaning lvalue conversion that discards qualifiers. But what if the object is a pointer? Qualifiers to the pointed-at data aren't affected by lvalue conversion.
Q1: What if the effective type is a pointer to qualified-type? Can I lvalue access it as a non-qualified pointer to the same type? Where in the standard is this stated?
The exceptions to the strict aliasing rule mention qualifiers in these cases:
— a qualified version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the effective type of the object,
— a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,None of these address qualifiers of the effective type itself, only by the lvalue used for access. Which should be quite irrelevant, because of lvalue conversion... right?
Q2: Does lvalue conversion happen before or after the above quoted rules of effective type/strict aliasing are applied?
Q3: Does the effective type come with qualifiers or not? Where in the standard is this stated?
"Qualified type" being a defined term, the definition is potentially relevant:
(C17 6.2.5/26)
I note that the
_Atomickeyword is different from the other three categorized as type qualifiers, and I presume that this is related to the fact that atomic types are not required to have the same representation or alignment requirements as their corresponding non-atomic types.I also note that the specification is explicit that qualified and unqualified versions of a type are different types.
With that background,
I take you to mean this:
The effective type of
xisconst uint32_t *(an unqualified pointer toconst-qualifieduint32_t), and it is being accessed via an lvalue of typeuint32_t *(an unqualified pointer to unqualifieduint32_t). This combination is not among the exceptions allowed by the language spec. In particular,uint32_t *is not a qualified version of aconst uint32_t *. The resulting behavior is therefore undefined, as specified in C17 6.5, paragraphs 6 and 7.Although the standard does not discuss this particular application of the SAR, I take it to be justified indirectly. The issue in cases such as this is not so much about accessing the pointer value itself as about producing a pointer whose type discards qualifiers of the pointed-to type.
Note also that the SAR does allow this variation:
, as
const uint32_t * constis a qualified version ofconst uint32_t *.I don't see how lvalue conversion could be construed to apply before strict aliasing. The strict aliasing rule is expressed in terms of the lvalues used for accessing objects, and the result of lvalue conversion is not an lvalue.
Additionally, as @EricPostpischil observed, the SAR applies to all accesses, which include writes. There is no lvalue conversion in the first place for an lvalue that is being written.
Qualified and unqualified versions of a type are different types. I see no justification for interpreting the paragraph 6.5/6's "the declared type of the object" or "the type of the lvalue" as if the type were supposed to be considered stripped of its qualifiers, much less as if all qualifiers in the type(s) from which it is derived were stripped. The words "the type" mean what they say.