Search code examples
c++gcclambdainitializationcompiler-warnings

Different notes for uninitialized member inside a generic lambda in GCC 9 and GCC 10


I have noticed an inconsistent behavior in my production C++17 code regarding generic lambdas and notes. I was finally able to break it down to the following minimal example.

Gives a note with x86_64 gcc 9.3, but NOT with x86_64 gcc 10.1

#include <string>
#include <iostream>

struct STR { int a; };

int main() 
{
    auto lambda = 
        []( const auto& executionContext )
        {
            if ( !executionContext.empty() )
                return;

            STR objSTR;
            objSTR.a = 666;
            std::cout << objSTR.a;
        };
    
    lambda( std::string{} );

    return 0;
}

The compiler message is as follows:

<source>: In instantiation of 'main()::<lambda(const auto:1&)> [with auto:1 = std::__cxx11::basic_string<char>]':
<source>:19:31:   required from here
<source>:4:12: note: 'struct STR' has no user-provided default constructor
    4 |     struct STR { int a; };
      |            ^~~
<source>:4:22: note: and the implicitly-defined constructor does not initialize 'int STR::a'
    4 |     struct STR { int a; };
      |                      ^

What is the note good for? I initialise my structure correctly with 666. As far as I know, this is correct C++ code and does not require any note/reference about/to possible uninitialised dangers.

Interestingly, if I now replace auto with std::string, the note disappears completely. So suddenly no note is necessary here?

Gives no note with x86_64 gcc 9.3 and with x86_64 gcc 10.1

#include <string>
#include <iostream>

struct STR { int a; };

int main() 
{
    auto lambda = 
        []( const std::string& executionContext )
        {
            if ( !executionContext.empty() )
                return;

            STR objSTR;
            objSTR.a = 666;
            std::cout << objSTR.a;
        };
    
    lambda( std::string{} );

    return 0;
}

I can get ONLY rid of the note for the generic lambda if I use value initialization as follows:

Gives no note with x86_64 gcc 9.3 and with x86_64 gcc 10.1

#include <string>
#include <iostream>

struct STR { int a; };

int main() 
{
    auto lambda = 
        []( const auto& executionContext )
        {
            if ( !executionContext.empty() )
                return;

            STR objSTR{}; //FORCED to add {} to get rid of the note
            objSTR.a = 666;
            std::cout << objSTR.a;
        };
    
    lambda( std::string{} );

    return 0;
}

To me, it feels like a bug when in a template context like a generic lambda you are suddenly forced to use value initialisation for a simple struct when you don't want to have this note. The fact that the note no longer appears in such a context as of GCC 10.1 emphasises the argumentation for me.

The concrete, unambiguous question is:
=> Can you confirm that this is a bug in GCC 9.3?

Online demo: https://godbolt.org/z/E7xeP91xd Flags: -Wall -Wextra -O3 -std=c++17
Compiler: x86_64 gcc 9.3/x86_64 gcc 10.1


Solution

  • The note in GCC 9.3 about the uninitialized member in struct STR is technically correct because the default constructor does not initialize int a.

    GCC 10.1 may have relaxed this check or improved its context awareness for generic lambdas. Initializing objSTR with {} is a good practice to ensure members are initialized. If the note is annoying but harmless, you can safely ignore it or initialize the struct explicitly. Different compiler versions often have variations in their warning and note behaviors, which can explain the observed inconsistency.