lundi 13 juillet 2020

GCC throws init-list-lifetime warning on potentially valid code?

I'm running on Debian unstable with GCC 9.3.0.

There was a recent change on a project I work on that introduced the below code.

decltype(VpiIterator::iterate_over) VpiIterator::iterate_over = []{
    /* for reused lists */
    std::initializer_list<int32_t> module_options;
    std::initializer_list<int32_t> struct_options;

    return decltype(VpiIterator::iterate_over) {
        {vpiModule, module_options = {
            //...
        }},
        {vpiGenScope, module_options},

        {vpiStructVar, struct_options = {
            //...
        }},
        {vpiStructNet, struct_options},

        //...
    };
}();

Identical subsections of the initializer lists are first declared at the top, defined and assigned to the std:initializer_list variable at the first usage, then used in multiple places. This is convenient, and some may argue more readable, which is why it was accepted.

All was well until a few days ago where the code started throwing the below warning. We use -Werror in our regression, so this fails for me. I also tried with clang 9.0.1, which does not throw the warning.

  gcc -pthread -B /home/kaleb/miniconda3/compiler_compat -Wl,--sysroot=/ -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -DVPI_CHECKING=1 -DMODELSIM= -Icocotb/share/include -I/home/kaleb/miniconda3/include/python3.7m -c cocotb/share/lib/vpi/VpiCbHdl.cpp -o build/temp.linux-x86_64-3.7/cocotb/share/lib/vpi/VpiCbHdl.o -std=c++11 -Wall -Wextra -Wcast-qual -Wwrite-strings -Wconversion -Wnon-virtual-dtor -Woverloaded-virtual -D__STDC_FORMAT_MACROS
  cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for C/ObjC but not for C++
  cocotb/share/lib/vpi/VpiCbHdl.cpp: In lambda function:
  cocotb/share/lib/vpi/VpiCbHdl.cpp:600:9: warning: assignment from temporary initializer_list does not extend the lifetime of the underlying array [-Winit-list-lifetime]
    600 |         }},
        |         ^
  cocotb/share/lib/vpi/VpiCbHdl.cpp:616:9: warning: assignment from temporary initializer_list does not extend the lifetime of the underlying array [-Winit-list-lifetime]
    616 |         }},
        |         ^

According to cppreference:

The underlying array is not guaranteed to exist after the lifetime of the original initializer list object has ended. The storage for std::initializer_list is unspecified (i.e. it could be automatic, temporary, or static read-only memory, depending on the situation).

So my understanding is that the common initializer list value, being defined within the scope of an encompassing initializer list, has a lifetime that ends with the enclosing initializer list. From the cppreference page earlier, it mentions that std::initializer_list is a "lightweight proxy-object", which implies that it does not take ownership of the temporary object or extend it's lifetime. This means that the underlying array is not guaranteed to exist in later usage, which is why the warning is being thrown. Is this analysis correct?

I can prevent the warning from occuring by moving the std::initializer_list variable initialization to the declaration. For full details on the change see the PR.

Aucun commentaire:

Enregistrer un commentaire