• GCC bug

    From Andrey Tarasevich@noone@noone.net to comp.lang.c on Wed Sep 10 06:51:49 2025
    From Newsgroup: comp.lang.c

    An attempt to use designated initializers to explicitly re-initialize a sub-member `y` of a struct member `b.a`

    #include <stdio.h>

    struct A { int x, y; };
    struct B { struct A a; };

    int main(void)
    {
    struct A ia = { 1, 2 };
    struct B b = { .a = ia, .a.y = 42 };
    printf("%d %d\n", b.a.x, b.a.y);
    }

    GCC outputs:

    0 42

    I.e. it does initialize `b.a.y` with `42`, but for some reason also
    produces zero in `b.a.x`. Meanwhile, Clang, MSVC output

    1 42

    as expected.

    The funny part is that this exact functionality is actually directly illustrated by the standard in "6.7.11 Initialization" example 12.

    Is it just a bug or is there some defiant reasoning (e.g. "we know
    better") for GCC's behavior?
    --
    Best regards,
    Andrey
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Wed Sep 10 17:45:14 2025
    From Newsgroup: comp.lang.c

    On Wed, 10 Sep 2025 06:51:49 -0700
    Andrey Tarasevich <noone@noone.net> wrote:

    An attempt to use designated initializers to explicitly re-initialize
    a sub-member `y` of a struct member `b.a`

    #include <stdio.h>

    struct A { int x, y; };
    struct B { struct A a; };

    int main(void)
    {
    struct A ia = { 1, 2 };
    struct B b = { .a = ia, .a.y = 42 };
    printf("%d %d\n", b.a.x, b.a.y);
    }

    GCC outputs:

    0 42

    I.e. it does initialize `b.a.y` with `42`, but for some reason also
    produces zero in `b.a.x`. Meanwhile, Clang, MSVC output

    1 42

    as expected.


    Are you sure about MSVC?
    I tested both with VS2017 and with VS2022. Both printed '0 42'.
    The same for all versions of ICC* that I found on godbolt.

    For easier observation on Godbolt I reduced you code to following:

    struct A { int x, y; };
    struct B { struct A a; };

    struct B foo(void)
    {
    struct A ia = { 1, 2 };
    struct B b = { .a = ia, .a.y = 42 };
    return b;
    }



    * - not to be confused with ICX which is Intel's distro of clang/LLVM.



    The funny part is that this exact functionality is actually directly illustrated by the standard in "6.7.11 Initialization" example 12.

    Is it just a bug or is there some defiant reasoning (e.g. "we know
    better") for GCC's behavior?


    Try their bugzilla and please post the link to conversion here.
    I am grabbing the popcorn.


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Andrey Tarasevich@noone@noone.net to comp.lang.c on Wed Sep 10 21:15:00 2025
    From Newsgroup: comp.lang.c

    On Wed 9/10/2025 7:45 AM, Michael S wrote:

    Are you sure about MSVC?
    I tested both with VS2017 and with VS2022. Both printed '0 42'.

    I simply tried it on whatever was currently installed on my machine,
    without giving it too much thought, and it printed `1 42` right away. It
    is VS2022.

    Just checked the version. It identifies itself as "Version 17.14.6 (June 2025)".
    --
    Best regards,
    Andrey





    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Damien Wyart@damien.wyart@free.fr to comp.lang.c on Thu Sep 11 09:36:38 2025
    From Newsgroup: comp.lang.c

    * Andrey Tarasevich <noone@noone.net> in comp.lang.c:
    [...]
    Is it just a bug or is there some defiant reasoning (e.g. "we know
    better") for GCC's behavior?

    Indeed, I found this which seems to confirm: https://stackoverflow.com/questions/40920714/is-full-followed-by-partial-initialization-of-a-subobject-undefined-behavior

    (but I could't find anything in gcc bugzilla)
    --
    DW
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Michael S@already5chosen@yahoo.com to comp.lang.c on Thu Sep 11 11:57:41 2025
    From Newsgroup: comp.lang.c

    On Wed, 10 Sep 2025 21:15:00 -0700
    Andrey Tarasevich <noone@noone.net> wrote:

    On Wed 9/10/2025 7:45 AM, Michael S wrote:

    Are you sure about MSVC?
    I tested both with VS2017 and with VS2022. Both printed '0 42'.

    I simply tried it on whatever was currently installed on my machine,
    without giving it too much thought, and it printed `1 42` right away.
    It is VS2022.

    Just checked the version. It identifies itself as "Version 17.14.6
    (June 2025)".


    I tested several x64 version that I have on two computers on my desk.

    VS2013
    Microsoft (R) C/C++ Optimizing Compiler Version 18.00.31101 for x64


    VS2017
    Microsoft (R) C/C++ Optimizing Compiler Version 19.16.27054 for x64


    VS2022 LTSC 17.2
    Microsoft (R) C/C++ Optimizing Compiler Version 19.32.31342 for x64


    VS2022
    Microsoft (R) C/C++ Optimizing Compiler Version 19.44.35215 for x64

    All printed "0 42"
    With -W4 or -Wall they gave interesting warning:
    1.c(9): warning C4189: 'ia': local variable is initialized but not
    referenced


    I don't know if compiler in "Visual Studio 2022 Version 17.13.6" is
    newer or older than 19.44.35215. Microsoft's site does not report full
    compiler versions, so it seems that the only way to know is to open
    command prompt and run 'cl'. But my guess is that it is a little older.
    So, obviously, we are doing something differently.

    I compile from command line as following:
    cl -MD -Wall -O1 1.c

    My guess is that you compile from VS GUI and that your GUI configured
    to use clang/LLVM tools instead of MSVC.


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Andrey Tarasevich@noone@noone.net to comp.lang.c on Thu Sep 11 05:11:03 2025
    From Newsgroup: comp.lang.c

    On Thu 9/11/2025 1:57 AM, Michael S wrote:

    My guess is that you compile from VS GUI and that your GUI configured
    to use clang/LLVM tools instead of MSVC.

    You are spot on. I'm sorry for misinformation.

    I don't normally use clang/LLVM toolchain under MSVC, but apparently I switched my scratch-test project to clang a while ago - just to test
    something - and forgot about it entirely.

    Indeed, MSVC toolchain suffers from the same issue as GCC: it also
    prints `0 42`.
    --
    Best regards,
    Andrey
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Andrey Tarasevich@noone@noone.net to comp.lang.c on Thu Sep 11 05:28:30 2025
    From Newsgroup: comp.lang.c

    On Thu 9/11/2025 12:36 AM, Damien Wyart wrote:
    * Andrey Tarasevich <noone@noone.net> in comp.lang.c:
    [...]
    Is it just a bug or is there some defiant reasoning (e.g. "we know
    better") for GCC's behavior?

    Indeed, I found this which seems to confirm: https://stackoverflow.com/questions/40920714/is-full-followed-by-partial-initialization-of-a-subobject-undefined-behavior

    (but I could't find anything in gcc bugzilla)

    Yes, that's the same issue.

    It appears that full `.a = ia` initializer leaves/resets `.a` member in
    some sort of pseudo-uninitilized state, which causes a subsequent `.a.y
    = 42` initializer to fully re-initialize `.a`.

    This version

    struct B b = { .a = ia, .a.y = 42, .a.x = 43 };
    printf("%d %d\n", b.a.x, b.a.y);

    outputs

    43 42

    indicating that `.a.x = 43` further down the line did not trigger full re-initialization of `.a`.

    Meanwhile, this version

    struct B b = { .a = ia, .a.y = 42, .a.x = 43, .a = ia, .a.x = 43 };
    printf("%d %d\n", b.a.x, b.a.y);

    outputs

    43 0

    i.e. the second `.a = ia` initializer "reset" this anomalous behavior.
    --
    Best regards,
    Andrey
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Andrey Tarasevich@noone@noone.net to comp.lang.c on Thu Sep 11 19:04:56 2025
    From Newsgroup: comp.lang.c

    On Wed 9/10/2025 6:51 AM, Andrey Tarasevich wrote:
    An attempt to use designated initializers to explicitly re-initialize a sub-member `y` of a struct member `b.a`

      #include <stdio.h>

      struct A { int x, y; };
      struct B { struct A a; };

      int main(void)
      {
        struct A ia = { 1, 2 };
        struct B b = { .a = ia, .a.y = 42 };
        printf("%d %d\n", b.a.x, b.a.y);
      }

    GCC outputs:

      0 42

    I.e. it does initialize `b.a.y` with `42`, but for some reason also
    produces zero in `b.a.x`. Meanwhile, Clang, MSVC output

      1 42

    as expected.


    An interesting detail is that the issue disappears when plain
    initializer list is used to initialize `.a`

    struct B b = { .a = { 1, 2 }, .a.y = 42 };
    printf("%d %d\n", b.a.x, b.a.y);
    // Outputs: 1 42

    With a compound literal as initializer, the bug reappears

    struct B b = { .a = (struct A) { 1, 2 }, .a.y = 42 };
    printf("%d %d\n", b.a.x, b.a.y);
    // Outputs: 0 42

    I.e. the issue reveals itself when initializer is represented by an
    object (named or unnamed), an lvalue.
    --
    Best regards,
    Andrey
    --- Synchronet 3.21a-Linux NewsLink 1.2