Skip to content

Add a guid constructor overload taking Data4 by reference to array - #1622

Open
Daniel Jump (DanielJump) wants to merge 1 commit into
microsoft:masterfrom
DanielJump:warnings-guid-ctor
Open

Add a guid constructor overload taking Data4 by reference to array#1622
Daniel Jump (DanielJump) wants to merge 1 commit into
microsoft:masterfrom
DanielJump:warnings-guid-ctor

Conversation

@DanielJump

@DanielJump Daniel Jump (DanielJump) commented Sep 1, 2026

Copy link
Copy Markdown
Member

The guid constructor takes Data4 as std::array<std::uint8_t, 8> const&. Because std::array wraps a C array, a braced call site elides the inner braces, and MSVC reports C5246 (the initialization of a subobject should be wrapped in braces) at each such call site - including the guid literals C++/WinRT generates for every namespace header.

Change

Add an overload taking std::uint8_t const (&)[8] alongside the existing std::array one, rather than replacing it. A braced initializer binds to the C array directly, so there is no intervening subobject and no warning, and callers that pass a std::array keep compiling unchanged.

Why not suppress it at the constructor

The diagnostic is attributed to the caller, not to the constructor definition, so a push / disable / pop around the constructor has no effect:

variant C5246
std::array parameter, braced call site 1, reported at the call site
same, with warning(push/disable: 5246/pop) around the constructor 1, unchanged
same, call site double-braced {{...}} 0
std::uint8_t const (&)[8] parameter 0

Suppressing would therefore have to happen at every call site, which includes all of the generated namespace headers and any guid a consumer writes.

Why an overload rather than changing the parameter

Replacing the parameter is source-breaking for callers passing a std::array lvalue:

error C2440: 'initializing': cannot convert from 'initializer list' to 'guid'

Adding the overload avoids that. I checked that it does not introduce ambiguity, on MSVC and clang-cl, for braced-init-lists, const and non-const std::array lvalues, std::array temporaries, and C array lvalues - all five compile clean with no C5246 and no -Wmissing-braces.

Validation

/Wall, MSVC x64, /std:c++20 /permissive-, on a translation unit exercising collections, coroutines, delegates, implements, factories and classic COM:

  • C5246: 114 -> 20
  • no errors, and no change to any other diagnostic (C4265 x15, C4365 x21, C4946 x16 before and after)

@YexuanXiao

Yexuan Xiao (YexuanXiao) commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Does the following code not work? It can avoid source-breaking.

#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(push)
#pragma warning(disable: 5246)
        constexpr guid(std::uint32_t const Data1, std::uint16_t const Data2, std::uint16_t const Data3, std::uint8_t const (&Data4)[8]) noexcept : 
              Data1(Data1), 
              Data2(Data2), 
              Data3(Data3), 
              Data4{ Data4[0], Data4[1], Data4[2], Data4[3], Data4[4], Data4[5], Data4[6], Data4[7] } 
          { 
          }
#pragma warning(pop)
#endif

@DanielJump
Daniel Jump (DanielJump) marked this pull request as ready for review September 1, 2026 20:41
The guid constructor takes Data4 as std::array<std::uint8_t, 8> const&.
Because std::array wraps a C array, a braced call site elides the inner
braces and MSVC reports C5246, "the initialization of a subobject should be
wrapped in braces", at every such call site - including the guid literals
C++/WinRT generates for each namespace header.

Suppressing the warning around the constructor does not work, because the
diagnostic is attributed to the caller rather than to the constructor.

Add an overload taking std::uint8_t const (&)[8] rather than replacing the
existing parameter. A braced initializer then binds to the C array directly,
with no intervening subobject and no warning, while callers passing a
std::array continue to compile unchanged.

Measured on a /Wall build of a translation unit exercising collections,
coroutines, delegates, implements, factories and classic COM: C5246 falls
from 114 to 20, with no other diagnostic changes.
@DanielJump Daniel Jump (DanielJump) changed the title Take Data4 as a reference to array in the guid constructor Add a guid constructor overload taking Data4 by reference to array Sep 1, 2026
@DanielJump

Copy link
Copy Markdown
Member Author

Thanks for looking. I tried exactly that, and the suppression turns out not to take effect: C5246 is attributed to the call site rather than to the constructor, so a push / disable / pop around the constructor leaves it in place.

Reduced repro, MSVC x64, /std:c++20 /permissive- /Wall:

struct G {
    std::uint32_t D1; std::uint16_t D2; std::uint16_t D3; std::uint8_t D4[8];
    G() = default;
    constexpr G(std::uint32_t d1, std::uint16_t d2, std::uint16_t d3, std::array<std::uint8_t,8> const& d4) noexcept
      : D1(d1), D2(d2), D3(d3), D4{d4[0],d4[1],d4[2],d4[3],d4[4],d4[5],d4[6],d4[7]} {}
};
constexpr G g1{ 1,2,3, {1,2,3,4,5,6,7,8} };   // <-- warning lands here
variant C5246
as above 1, reported on the g1 line
warning(push/disable: 5246/pop) around the constructor 1, unchanged
call site double-braced {{...}} 0
parameter changed to std::uint8_t const (&)[8] 0

To suppress it we would have to do so at every call site, which means all of the generated namespace headers plus any guid a consumer writes themselves.

You are right about the source break, though, and thanks for catching it - replacing the parameter does break callers that pass a std::array lvalue:

error C2440: 'initializing': cannot convert from 'initializer list' to 'G'

So I have pushed a different fix: add the std::uint8_t const (&)[8] overload instead of replacing the std::array one. A braced initializer binds to the C array directly, with no subobject and no warning, and existing std::array callers are unaffected.

I checked for ambiguity across every call shape I could think of, on both MSVC and clang-cl - braced-init-list, const and non-const std::array lvalue, std::array temporary, and C array lvalue. All five compile clean, no C5246, no -Wmissing-braces.

Net effect on a /Wall build of a translation unit exercising collections, coroutines, delegates, implements, factories and classic COM: C5246 goes from 114 to 20, with no other diagnostic changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants