4

I am getting a warning (turned into an error with -Werror) about missing-field-initializers when using designated initializers for the fields in my struct, because I'm not initializing fields in a 3rd party base class, boost::intrusive::unordered_set_base_hook

error: missing initializer for member ‘foo::boost::intrusive::unordered_set_base_hook<>’
      [-Werror=missing-field-initializers]

   10 |     foo f { .bar = 1 };
      |                      ^

Here is a minimal reproducible example:

#include <boost/intrusive/unordered_set.hpp>

struct foo : boost::intrusive::unordered_set_base_hook<>
{
    int bar;
};

int main()
{
    foo f { .bar = 1 };
    return 0;
}

Here is my CMakeLists.txt file. I am specifying that the boost include dir is a SYSTEM directory, to suppress warnings from boost headers.

cmake_minimum_required(VERSION 3.18)
project(scratch_test)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Boost)

add_executable(scratch
    main.cpp
)

target_compile_options(scratch
    PRIVATE
        -Wmissing-field-initializers
        -Werror
)

target_include_directories(scratch
    SYSTEM PRIVATE
        ${Boost_INCLUDE_DIRS}
)

Looking at the source code for boost::intrusive, in effect the code effectively looks like this:

struct generic_hook
{
    void* next_;
};

struct unordered_set_base_hook : generic_hook
{
};

So indeed next_ is not initialized.

I even tried to modify my code to use my own base class, which I in-class initialize to nullptr:

struct generic_hook
{
    void* next_ {nullptr};
};

struct unordered_set_base_hook : generic_hook
{
};

struct foo : unordered_set_base_hook
{
    int bar;
};

int main()
{
    foo f { .bar = 1 };
    return 0;
}

I still get the error:

error: missing initializer for member ‘foo::unordered_set_base_hook’ 
      [-Werror=missing-field-initializers]

   17 |     foo f { .bar = 1 };
      |                      ^

Is this a legitimate warning/error?

I do not really want to be responsible for initializing 3rd party dependency base class members; what is the correct course of action here?

4
  • 3
    Reproduced only on GCC. Seems like a GCC bug. Commented Oct 2 at 10:11
  • 1
    @TheAliceBaskerville That's for missing designated field initializers, of which there are none missing in Foo{ .bar = 1 }. It's missing an initializer for the base class field, missing-field-initializers is wider than missing-designated-field-initializers. Commented Oct 2 at 14:26
  • 2
    @TheAliceBaskerville Ok, it seems clang does have that warning. Clang uses the separate missing-designated-field-initializers that is also enabled by -Wmissing-field-initializers when you use designated initializers, and Clang only checks if non-static data members are initialized: github.com/llvm/llvm-project/blob/… (field_iterator only iterates over non-static data members), so skips over base classes. Maybe it is a GCC bug, but GCC is warning about a subobject without an explicit initializer Commented Oct 2 at 14:59
  • @Artyer I guess it boils down to whether this check should trigger in cases with a missing explicit initializer for the base class subobject. Personally, that seems weird, as it is impossible to initialize a base class subobject with a designated initializer. But I know nothing about the design decisions in any of these compilers. Some mismatch in behavior is present for sure, so the comment in the code you link to is incorrect: // This matches gcc behaviour. Commented Oct 2 at 15:08

1 Answer 1

7

The error is not about void* next_ being uninitialized, but about you not providing an explicit initializer for something in your class. This warning is meant to warn you if you accidentally forget that a base class or data member exists when initializing, most useful for cases like:

struct Foo {
    int x;
    int y;
    int z;
};

Foo f{ .x = 1, .z = 2 };  // Forgot to provide an initializer for y, should write .y = 0 or .y = {}.

There's currently no way to use designated intializers with base classes, so you would have to write:

int main()
{
    foo f { boost::intrusive::unordered_set_base_hook<>(), 1 };
    // Or
    foo f { {}, 1 };
    return 0;
}

Aggregate initialization is kind of a pain in general if there are base classes, I would recommend just writing a constructor if you want to keep the error. Or use -Wno-error=missing-field-initializers to downgrade to a warning or -Wno-missing-field-initializers to silence completely.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.