Version
master (856eaff). Measurements below were taken against the generated projection in windowssdkcppwinrt.10.21320.2, with the strings/ fixes validated at master.
Summary
C++/WinRT headers cannot be compiled at high warning levels. Consumers are forced to wrap every include in #pragma warning blocks. We repackage cppwinrt for the Office monorepo and currently inject a 19-warning push/disable prologue into every generated header as a post-generate step, which is unsatisfying and hides real diagnostics in adjacent code.
I went through that whole suppression list to work out which entries are genuine defects in cppwinrt rather than noise. Most of them are, and all of them are fixable. This issue is to track that; the pull requests are linked at the bottom.
MSVC, measured on the repro below at /Wall:
| Code |
x64 |
x86 |
Cause |
| C5246 |
114 |
114 |
std::array aggregate init needs two brace levels. The guid constructor alone accounts for 57 of these, one per generated guid |
| C4365 |
21 |
31 |
integral promotion, plus uint32_t to ptrdiff_t iterator arithmetic that only shows up on 32-bit |
| C4946 |
16 |
16 |
reinterpret_cast between related classes. Every abi type derives from unknown_abi, so static_cast is correct |
| C4265 |
15 |
15 |
virtual functions with an accessible non-virtual destructor |
| C4826 |
0 |
1 |
reinterpret_cast of a pointer to int64_t sign-extends |
Six further codes we suppress (C4101, C4189, C4456, C4457, C4459, C5205) never fired in any configuration I tried, and C4458 is already suppressed internally by base_delegate.h. C6101 fires under /analyze but all instances are in the Windows SDK's WindowsNumerics.inl, not in cppwinrt.
clang (clang-cl 22.1.2), counting only the warnings we suppress:
| Warning |
Count |
Notes |
-Wnon-virtual-dtor |
184 |
see #1499 |
-Wunused-variable |
60 |
already fixed at master by [[maybe_unused]]; only affects older packages |
-Wnontrivial-memcall |
19 |
already fixed at master by making the base_array.h guard clang-aware |
-Wmissing-braces |
12 |
all in the SDK's DirectXMathMatrix.inl, not cppwinrt |
-Wshadow |
8 |
all in the MSVC STL, not cppwinrt |
So of 19 suppressed warnings, six are real defects in cppwinrt today, two are already fixed at master, and the rest are either stale or owned by the SDK and the STL.
Reproducible example
// cl /c /EHsc /std:c++20 /permissive- /await:strict /Wall repro.cpp
//
// Add /wd for the /Wall codes that are not about cppwinrt:
// 4514 4710 4711 4820 5045 4625 4626 5026 5027 4623 4571 4668 5039 4643 5262 4868 5204
//
// clang-cl /c /EHsc /std:c++20 -Wno-everything -Wnon-virtual-dtor repro.cpp
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
using namespace winrt;
using namespace Windows::Foundation;
struct Widget : implements<Widget, IStringable>
{
hstring ToString() { return L"Widget"; }
};
IAsyncAction Run()
{
auto widget = make<Widget>();
auto vector = single_threaded_vector<hstring>({ widget.ToString() });
auto map = single_threaded_map<hstring, int32_t>();
map.Insert(vector.GetAt(0), 1);
co_return;
}
A wider translation unit that also exercises delegates, events, agile_ref, weak_ref, boxing and error handling reaches the counts in the table above.
Separately, to_hstring widens char to wchar_t through std::copy, which produces a C4365 that a caller cannot suppress, because the assignment happens inside <xutility>:
// cl /std:c++20 /W4 /w14365
#include <algorithm>
#include <iterator>
char narrow[8]{};
wchar_t wide[8]{};
wchar_t* widen() { return std::copy(std::begin(narrow), std::end(narrow), wide); }
Expected behavior
C++/WinRT headers compile without warnings at MSVC /Wall and under clang, so that consumers do not have to wrap includes in pragmas or globally relax their own analysis rules.
Actual behavior
The example above produces 96 warnings at /Wall on x64 (C5246 x67, C4365 x21, C4946 x7, C4265 x1) and 81 -Wnon-virtual-dtor under clang-cl.
The wider translation unit reaches 166 warnings on x64, 177 on x86, and 304 under clang.
With #1621, #1622 and #1623 applied it is 0 on x64, 0 on x86, and 0 attributable to cppwinrt under clang.
Additional comments
Related, both closed without a fix:
Pull requests
Split so the risk is separable. All three are green on CI.
| PR |
Change |
Warnings |
| #1621 |
Integral conversions and brace elision. Mechanical casts and brace pairs, plus an impl::abi_cast helper so the ABI conversions are correct for classic COM interfaces as well as WinRT ones. No signature or generated-file changes. |
C4365, C4946, C4826, and the non-guid C5246 |
| #1622 |
Adds a guid constructor overload taking std::uint8_t const (&)[8] alongside the existing std::array<std::uint8_t, 8> const& one. Additive, so nothing is source-breaking. |
C5246, 114 -> 20 on its own; the remainder is covered by #1621 |
| #1623 |
Scoped #pragma suppression of the destructor warnings in each generated header, after review feedback that changing the vtable layout of ABI types was not acceptable. |
C4265, -Wnon-virtual-dtor |
While measuring the above I also found that base_macros.h disables four warnings with no matching push / pop, so they leak into every translation unit that includes <winrt/base.h> and silently disable those warnings in the consumer's own code. That is an independent bug, filed as #1624 and fixed in #1625.
Happy to reshape or drop any of these if you would rather solve it differently.
Version
master (856eaff). Measurements below were taken against the generated projection in
windowssdkcppwinrt.10.21320.2, with thestrings/fixes validated at master.Summary
C++/WinRT headers cannot be compiled at high warning levels. Consumers are forced to wrap every include in
#pragma warningblocks. We repackage cppwinrt for the Office monorepo and currently inject a 19-warning push/disable prologue into every generated header as a post-generate step, which is unsatisfying and hides real diagnostics in adjacent code.I went through that whole suppression list to work out which entries are genuine defects in cppwinrt rather than noise. Most of them are, and all of them are fixable. This issue is to track that; the pull requests are linked at the bottom.
MSVC, measured on the repro below at
/Wall:std::arrayaggregate init needs two brace levels. Theguidconstructor alone accounts for 57 of these, one per generated guiduint32_ttoptrdiff_titerator arithmetic that only shows up on 32-bitreinterpret_castbetween related classes. Every abi type derives fromunknown_abi, sostatic_castis correctreinterpret_castof a pointer toint64_tsign-extendsSix further codes we suppress (C4101, C4189, C4456, C4457, C4459, C5205) never fired in any configuration I tried, and C4458 is already suppressed internally by
base_delegate.h. C6101 fires under/analyzebut all instances are in the Windows SDK'sWindowsNumerics.inl, not in cppwinrt.clang (clang-cl 22.1.2), counting only the warnings we suppress:
-Wnon-virtual-dtor-Wunused-variable[[maybe_unused]]; only affects older packages-Wnontrivial-memcallbase_array.hguard clang-aware-Wmissing-bracesDirectXMathMatrix.inl, not cppwinrt-WshadowSo of 19 suppressed warnings, six are real defects in cppwinrt today, two are already fixed at master, and the rest are either stale or owned by the SDK and the STL.
Reproducible example
A wider translation unit that also exercises delegates, events,
agile_ref,weak_ref, boxing and error handling reaches the counts in the table above.Separately,
to_hstringwidenschartowchar_tthroughstd::copy, which produces a C4365 that a caller cannot suppress, because the assignment happens inside<xutility>:Expected behavior
C++/WinRT headers compile without warnings at MSVC
/Walland under clang, so that consumers do not have to wrap includes in pragmas or globally relax their own analysis rules.Actual behavior
The example above produces 96 warnings at
/Wallon x64 (C5246 x67, C4365 x21, C4946 x7, C4265 x1) and 81-Wnon-virtual-dtorunder clang-cl.The wider translation unit reaches 166 warnings on x64, 177 on x86, and 304 under clang.
With #1621, #1622 and #1623 applied it is 0 on x64, 0 on x86, and 0 attributable to cppwinrt under clang.
Additional comments
Related, both closed without a fix:
-Wnon-virtual-dtorwarn #1499 reports-Wnon-virtual-dtorand suggestsvirtual ~type() noexcept = default;. That fix would be incorrect for an ABI type, since adding a virtual destructor adds a vtable slot and breaks binary compatibility (confirmed with/d1reportSingleClassLayout). Suppress non-virtual destructor warnings in the generated headers #1623 suppresses the warning inside the generated headers instead.CAExcludePathworkaround.Pull requests
Split so the risk is separable. All three are green on CI.
impl::abi_casthelper so the ABI conversions are correct for classic COM interfaces as well as WinRT ones. No signature or generated-file changes.guidC5246guidconstructor overload takingstd::uint8_t const (&)[8]alongside the existingstd::array<std::uint8_t, 8> const&one. Additive, so nothing is source-breaking.#pragmasuppression of the destructor warnings in each generated header, after review feedback that changing the vtable layout of ABI types was not acceptable.-Wnon-virtual-dtorWhile measuring the above I also found that
base_macros.hdisables four warnings with no matchingpush/pop, so they leak into every translation unit that includes<winrt/base.h>and silently disable those warnings in the consumer's own code. That is an independent bug, filed as #1624 and fixed in #1625.Happy to reshape or drop any of these if you would rather solve it differently.