-
Notifications
You must be signed in to change notification settings - Fork 264
Description
Version
master
Summary
I work on the Visual C++ team, where we regularly build popular open-source projects, including cppwinrt, with development versions of the MSVC Build Tools in order to find and fix regressions before they can ship and cause trouble for you. This also allows us to provide advance notice of breaking changes, which is the case here.
In the MSVC Build Tools 14.50 shipping in Visual Studio 2026 18.0, the /await compiler option is officially being deprecated. This is a command-line deprecation warning that does not break builds (even under /WX):
C:\Temp>type meow.cpp
int main() {}
C:\Temp>cl /EHsc /nologo /W4 /await meow.cpp
cl : Command line warning D9047 : option 'await' has been deprecated and will be removed in a future release.
Standard C++ coroutines are available by default in C++20 or later, or use '/await:strict' in earlier language modes.
meow.cpp
In the MSVC Build Tools 14.51 shipping in some future update to Visual Studio 2026, I am additionally deprecating the <experimental/coroutine>, <experimental/resumable>, and <experimental/generator> headers, as the first two have been superseded by C++20 <coroutine> and the third has been superseded by C++23 <generator>. This is a "hard deprecation" implemented as a static_assert. It can be acknowledged and silenced with an escape hatch macro, but future removal is coming. (PR: microsoft/STL#5804 )
We've found that cppwinrt conditionally includes <experimental/coroutine> in an unusual way. It begins by detecting support for Standard coroutines and prefers to include <coroutine> (good), but otherwise falls back to including <experimental/coroutine>. Interestingly, this is guarded by __has_include(<experimental/coroutine>) (which is always true, at least until I physically remove the header in the future), but not by detecting the /await compiler option (which is indicated by the _RESUMABLE_FUNCTIONS_SUPPORTED predefined macro):
cppwinrt/strings/base_includes.h
Lines 50 to 78 in dcaa98c
| #ifdef __cpp_lib_coroutine | |
| #include <coroutine> | |
| namespace winrt::impl | |
| { | |
| template <typename T = void> | |
| using coroutine_handle = std::coroutine_handle<T>; | |
| using suspend_always = std::suspend_always; | |
| using suspend_never = std::suspend_never; | |
| } | |
| #elif __has_include(<experimental/coroutine>) | |
| #include <experimental/coroutine> | |
| namespace winrt::impl | |
| { | |
| template <typename T = void> | |
| using coroutine_handle = std::experimental::coroutine_handle<T>; | |
| using suspend_always = std::experimental::suspend_always; | |
| using suspend_never = std::experimental::suspend_never; | |
| } | |
| #else | |
| #error C++/WinRT requires coroutine support, which is currently missing. Try enabling C++20 in your compiler. | |
| #endif |
This has affected several projects in our Real World Code test suite (MuseScore which uses cppwinrt, Qgroundcontrol which uses qtspeech which uses cppwinrt, Qt6 which uses cppwinrt). Interestingly, these projects don't appear to be compiling with deprecated /await - they are simply dragging in cppwinrt, which drags in <experimental/coroutine>, which now triggers my hard deprecation error. (I believe that previously, the experimental coroutine machinery wouldn't actually have been usable without /await, but nothing was trying to use it.)
I am not exactly sure how cppwinrt should change. I think there are a few options:
Option 1: Require Standard coroutines
You could simply require <coroutine>, drop the codepath for <experimental/coroutine>, and adjust your error message that currently says "Try enabling C++20 in your compiler." to additionally mention that /await:strict can be used to opt-in to Standard coroutines even for C++14/17 mode (this is less intrusive for projects that have difficulty quickly migrating to C++20).
Option 2: Detect deprecated /await
Instead of __has_include(<experimental/coroutine>), check for _RESUMABLE_FUNCTIONS_SUPPORTED. This would block "plain vanilla" usage of cppwinrt (i.e. usage in C++14/17 mode with neither /await nor /await:strict), forcing users to choose either the Standard or the deprecated path. Again it would be good to adjust the error message to mention /await:strict.
Option 3: Detect deprecated /await, otherwise don't error
Again check for _RESUMABLE_FUNCTIONS_SUPPORTED, but instead of emitting a compiler error for users in plain vanilla C++14/17 mode, simply don't include anything. It appears that several projects are managing minimal usage of cppwinrt without actually needing coroutines, as indicated by how they were compiling in plain vanilla C++14/17 mode, dragging in cppwinrt, which included <experimental/coroutine> (before my hard deprecation error), and then did nothing with it that actually needed coroutine support. I am not exactly sure if other code would need to be adjusted, but this is potentially the least invasive option for third-party projects that could allow them to continue compiling without needing to add /await:strict (or migrate to C++20).
Macro detection example
For completeness, here is how MSVC's macros work:
C:\Temp>type meow.cpp
#include <cstdio>
int main() {
#ifdef _RESUMABLE_FUNCTIONS_SUPPORTED
std::puts("Detected the deprecated /await compiler option.");
#endif
#ifdef __cpp_impl_coroutine
#if _MSVC_LANG > 201703L
std::puts("Detected support for standard coroutines, available in C++20.");
#else
std::puts("Detected support for standard coroutines, available with /await:strict in C++14/17.");
#endif
#endif
#if !defined(_RESUMABLE_FUNCTIONS_SUPPORTED) && !defined(__cpp_impl_coroutine)
std::puts("Detected nothing.");
#endif
}C:\Temp>(cl /EHsc /nologo /W4 /std:c++14 meow.cpp > NUL) && meow
Detected nothing.
C:\Temp>(cl /EHsc /nologo /W4 /std:c++14 /await meow.cpp > NUL) && meow
cl : Command line warning D9047 : option 'await' has been deprecated and will be removed in a future release.
Standard C++ coroutines are available by default in C++20 or later, or use '/await:strict' in earlier language modes.
Detected the deprecated /await compiler option.
C:\Temp>(cl /EHsc /nologo /W4 /std:c++14 /await:strict meow.cpp > NUL) && meow
Detected support for standard coroutines, available with /await:strict in C++14/17.
C:\Temp>(cl /EHsc /nologo /W4 /std:c++20 meow.cpp > NUL) && meow
Detected support for standard coroutines, available in C++20.
C:\Temp>(cl /EHsc /nologo /W4 /std:c++20 /await meow.cpp > NUL) && meow
cl : Command line warning D9047 : option 'await' has been deprecated and will be removed in a future release.
Standard C++ coroutines are available by default in C++20 or later, or use '/await:strict' in earlier language modes.
Detected the deprecated /await compiler option.
C:\Temp>(cl /EHsc /nologo /W4 /std:c++20 /await:strict meow.cpp > NUL) && meow
Detected support for standard coroutines, available in C++20.
(Here I'm using __cpp_impl_coroutine to detect compiler support for Standard coroutines, but it's fine and probably better for cppwinrt to use our library macro __cpp_lib_coroutine.)
Reproducible example
Expected behavior
No response
Actual behavior
No response
Additional comments
No response