• Type qualifiers and controlling expression of _Generic

    From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.std.c on Sat Oct 23 21:08:08 2021
    From Newsgroup: comp.std.c

    Ben Bacarisse <ben.usenet@bsb.me.uk> wrote in comp.lang.c++:

    I was curious so I tried this:

    #include <stdio.h>

    struct S { const int i; } s;
    struct S f(void) { return s; }

    int main(void)
    {
    const char *t =
    _Generic(f().i,
    int: "int",
    const int: "const int");
    puts(t);
    }

    f().i is not a lvalue and has a const-qualified type. gcc prints
    "int", but clang prints "const int". I think clang is right here.
    (So much for "they all copy gcc"!)

    After looking into this, I reach a different conclusion.

    First, despite the definition of lvalue conversion in 6.3.2.1 p2,
    it appears that it was never intended that lvalue conversion
    apply to expressions that are not evaluated. For C11, at the
    last minute the _Alignof operator was added as an exception for
    when lvalue conversions are done, but that was taken out again in
    C17, and still is not present in n2731, which I believe is the
    latest C2x draft. Also there is this defect report

    http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_423.htm

    dated October 8, 2012, which shows that the problem was recognized
    as a defect but not yet resolved about how to handle it. (That
    defect report is fairly long so I won't try to summarize it.)

    Second, the matter is addressed rather straightforwardly in C17
    and later in n2731 (which can be gotten here

    http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2731.pdf

    ), where 6.5.1.1 p2 (talking about _Generic) says in part

    The type of the controlling expression is the type of the
    expression as if it had undergone an lvalue conversion, [...]

    with a reference to a footnote

    An lvalue conversion drops type qualifiers.

    I should add that as best I can tell the same wording is used in
    C17 as in n2731 although I have not done a side-by-side comparison.

    Thus, I conclude that type qualifiers are removed by the "as if"
    lvalue conversion, whether or not the particular controlling
    expression is an lvalue. What gcc does is right, and clang just
    hasn't caught up to the latest corrections in this area.

    Disclaimer: I have not done any experimentation either with gcc
    or with clang to see how different versions or different option
    settings might affect their behaviors.
    --- Synchronet 3.19a-Linux NewsLink 1.113