diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3f3330ec..b3bda531d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -102,7 +102,7 @@ jobs: compiler: [MSVC, clang-cl] arch: [x86, x64, arm64] config: [Debug, Release] - test_exe: [test, test_cpp20, test_cpp20_no_sourcelocation, test_fast, test_slow, test_old, test_module_lock_custom, test_module_lock_none] + test_exe: [test, test_cpp20, test_cpp20_no_sourcelocation, test_cpp23, test_fast, test_slow, test_old, test_module_lock_custom, test_module_lock_none] exclude: - arch: arm64 config: Debug diff --git a/CMakeLists.txt b/CMakeLists.txt index b6516ad3a..a7c3e6c4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,8 +13,8 @@ project(cppwinrt LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED True) -set(CPPWINRT_BUILD_VERSION "2.3.4.5" CACHE STRING "The version string used for cppwinrt.") -if(CPPWINRT_BUILD_VERSION STREQUAL "2.3.4.5" OR CPPWINRT_BUILD_VERSION STREQUAL "0.0.0.0") +set(CPPWINRT_BUILD_VERSION "1.2.3.4" CACHE STRING "The version string used for cppwinrt.") +if(CPPWINRT_BUILD_VERSION STREQUAL "1.2.3.4" OR CPPWINRT_BUILD_VERSION STREQUAL "0.0.0.0") message(WARNING "CPPWINRT_BUILD_VERSION has been set to a dummy version string. Do not use in production!") endif() message(STATUS "Using version string: ${CPPWINRT_BUILD_VERSION}") diff --git a/Directory.Build.Props b/Directory.Build.Props index a2c760fd6..17ee02087 100644 --- a/Directory.Build.Props +++ b/Directory.Build.Props @@ -37,7 +37,7 @@ - 2.3.4.5 + 1.2.3.4 $(Platform) x86 $(SolutionDir)_build\$(CppWinRTPlatform)\$(Configuration)\ diff --git a/build_test_all.cmd b/build_test_all.cmd index 9f0457250..18a6d50e9 100644 --- a/build_test_all.cmd +++ b/build_test_all.cmd @@ -45,6 +45,7 @@ call msbuild /p:Configuration=%target_configuration%,Platform=%target_platform%, call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.slnx /t:test\test call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.slnx /t:test\test_cpp20 call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.slnx /t:test\test_cpp20_no_sourcelocation +call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.slnx /t:test\test_cpp23 call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.slnx /t:test\test_fast call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.slnx /t:test\test_slow call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.slnx /t:test\test_module_lock_custom diff --git a/cppwinrt.slnx b/cppwinrt.slnx index 150ad0cec..e6655a88e 100644 --- a/cppwinrt.slnx +++ b/cppwinrt.slnx @@ -47,6 +47,10 @@ + + + + diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index bd4e59d96..64d25a741 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -2646,7 +2646,7 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable type, bind(signature), bind(signature), - bind("(*this)", signature)); + bind("static_cast(*this)", signature)); } static void write_delegate_definition(writer& w, TypeDef const& type) diff --git a/run_tests.cmd b/run_tests.cmd index 77d883642..2a0f4465c 100644 --- a/run_tests.cmd +++ b/run_tests.cmd @@ -11,6 +11,7 @@ if "%target_configuration%"=="" set target_configuration=Debug call :run_test test call :run_test test_cpp20 call :run_test test_cpp20_no_sourcelocation +call :run_test test_cpp23 call :run_test test_fast call :run_test test_slow call :run_test test_old diff --git a/strings/base_delegate.h b/strings/base_delegate.h index c291ce1a2..90db75a68 100644 --- a/strings/base_delegate.h +++ b/strings/base_delegate.h @@ -125,11 +125,11 @@ WINRT_EXPORT namespace winrt::impl { if constexpr (std::is_void_v) { - (*this)(args...); + static_cast(*this)(args...); } else { - return (*this)(args...); + return static_cast(*this)(args...); } } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ed1515526..6e7cb4df1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -107,6 +107,7 @@ set(SKIP_LARGE_PCH FALSE CACHE BOOL "Skip building large precompiled headers.") add_subdirectory(test) add_subdirectory(test_cpp20) add_subdirectory(test_cpp20_no_sourcelocation) +add_subdirectory(test_cpp23) if(HAS_WINDOWSNUMERICS) add_subdirectory(old_tests) diff --git a/test/catch.hpp b/test/catch.hpp index ec03d85e3..b0e796a31 100644 --- a/test/catch.hpp +++ b/test/catch.hpp @@ -677,12 +677,12 @@ namespace Catch { auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; - constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + constexpr auto operator ""_sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { return StringRef( rawChars, size ); } } // namespace Catch -constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { +constexpr auto operator ""_catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { return Catch::StringRef( rawChars, size ); } @@ -3177,8 +3177,8 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val); - Detail::Approx operator "" _a(unsigned long long val); + Detail::Approx operator ""_a(long double val); + Detail::Approx operator ""_a(unsigned long long val); } // end namespace literals template<> @@ -7922,10 +7922,10 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val) { + Detail::Approx operator ""_a(long double val) { return Detail::Approx(val); } - Detail::Approx operator "" _a(unsigned long long val) { + Detail::Approx operator ""_a(unsigned long long val) { return Detail::Approx(val); } } // end namespace literals diff --git a/test/test_cpp20/test_cpp20.vcxproj b/test/test_cpp20/test_cpp20.vcxproj index f8eacff83..1795ca310 100644 --- a/test/test_cpp20/test_cpp20.vcxproj +++ b/test/test_cpp20/test_cpp20.vcxproj @@ -108,14 +108,6 @@ true true - - - - - - - - @@ -130,14 +122,6 @@ Console - - - - - - - - @@ -152,14 +136,6 @@ Console - - - - - - - - @@ -174,14 +150,6 @@ Console - - - - - - - - @@ -200,14 +168,6 @@ true true - - - - - - - - @@ -226,14 +186,6 @@ true true - - - - - - - - diff --git a/test/test_cpp23/CMakeLists.txt b/test/test_cpp23/CMakeLists.txt new file mode 100644 index 000000000..d459cdd20 --- /dev/null +++ b/test/test_cpp23/CMakeLists.txt @@ -0,0 +1,23 @@ +set(CMAKE_CXX_STANDARD 23) + +file(GLOB TEST_SRCS + LIST_DIRECTORIES false + CONFIGURE_DEPENDS + *.cpp +) +list(FILTER TEST_SRCS EXCLUDE REGEX "/(main|pch)\\.cpp") + +add_executable(test_cpp23 main.cpp ${TEST_SRCS}) + +target_precompile_headers(test_cpp23 PRIVATE pch.h) +set_source_files_properties( + main.cpp + PROPERTIES SKIP_PRECOMPILE_HEADERS true +) + +add_dependencies(test_cpp23 build-cppwinrt-projection) + +add_test( + NAME test_cpp23 + COMMAND "$" ${TEST_COLOR_ARG} +) diff --git a/test/test_cpp23/delegate_deducing_this.cpp b/test/test_cpp23/delegate_deducing_this.cpp new file mode 100644 index 000000000..38c058854 --- /dev/null +++ b/test/test_cpp23/delegate_deducing_this.cpp @@ -0,0 +1,129 @@ +#include "pch.h" + +using namespace winrt; +using namespace Windows::Foundation::Collections; + +#if defined(__cpp_explicit_this_parameter) && __cpp_explicit_this_parameter >= 202110L + +TEST_CASE("delegate") +{ + // <> + { + bool invoked = false; + delegate<> d = [&](this auto) { invoked = true; }; + d(); + REQUIRE(invoked); + } + + // + { + int result = 0; + delegate d = [&](this auto, int a) { result = a; }; + d(123); + REQUIRE(result == 123); + } + + // + { + int result = 0; + delegate d = [&](this auto, int a, int b) { result = a + b; }; + d(4,5); + REQUIRE(result == 9); + } + + // void() + { + bool invoked = false; + delegate d = [&](this auto) { invoked = true; }; + d(); + REQUIRE(invoked); + } + + // void(int) + { + int result = 0; + delegate d = [&](this auto, int a) { result = a; }; + d(123); + REQUIRE(result == 123); + } + + // void(int,int) + { + int result = 0; + delegate d = [&](this auto, int a, int b) { result = a + b; }; + d(4, 5); + REQUIRE(result == 9); + } + + // int() + { + delegate d = [](this auto) { return 123; }; + REQUIRE(d() == 123); + } + + // int(int) + { + delegate d = [](this auto, int a) { return a; }; + REQUIRE(d(123) == 123); + } + + // int(int,int) + { + delegate d = [](this auto, int a, int b) { return a + b; }; + REQUIRE(d(4, 5) == 9); + } +} + +TEST_CASE("typedeventhandler") +{ + using Handler = winrt::Windows::Foundation::TypedEventHandler; + + int called{}; + int sum{}; + + Handler handler = [&called, &sum](this auto, int sender, int args) + { + ++called; + sum = sender + args; + }; + + handler(1, 2); + + REQUIRE(called == 1); + REQUIRE(sum == 3); +} + +#if !(defined(_M_IX86) && !defined(_M_X64) && defined(__clang__)) +// Clang 20 target x86 generates incorrect code for this test. +// In observed_sender ctor (#1), this = X; in assignment operator (#2), this = X+16 (bytes). +// FIXME: Enable the test after Clang is fixed +TEST_CASE("observablevector_vectorchanged") +{ + IObservableVector vector = single_threaded_observable_vector(); + + int called{}; + IObservableVector observed_sender{ nullptr }; // #1 + CollectionChange change{}; + uint32_t index{}; + + auto token = vector.VectorChanged([&](this auto, IObservableVector sender, IVectorChangedEventArgs args) + { + ++called; + observed_sender = sender; // #2 + change = args.CollectionChange(); + index = args.Index(); + }); + + vector.Append(123); + + REQUIRE(called == 1); + REQUIRE(observed_sender == vector); + REQUIRE(change == CollectionChange::ItemInserted); + REQUIRE(index == 0); + + vector.VectorChanged(token); +} + +#endif + +#endif diff --git a/test/test_cpp23/main.cpp b/test/test_cpp23/main.cpp new file mode 100644 index 000000000..72f673a43 --- /dev/null +++ b/test/test_cpp23/main.cpp @@ -0,0 +1,30 @@ +#include +#define CATCH_CONFIG_RUNNER + +// Force reportFatal to be available on mingw-w64 +#define CATCH_CONFIG_WINDOWS_SEH + +#if defined(_MSC_VER) +#pragma warning(disable : 5311) +#endif + +#include "catch.hpp" +#include "winrt/base.h" + +using namespace winrt; + +int main(int const argc, char** argv) +{ + init_apartment(); + std::set_terminate([] { reportFatal("Abnormal termination"); ExitProcess(1); }); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); + return Catch::Session().run(argc, argv); +} + +CATCH_TRANSLATE_EXCEPTION(hresult_error const& e) +{ + return to_string(e.message()); +} diff --git a/test/test_cpp23/pch.cpp b/test/test_cpp23/pch.cpp new file mode 100644 index 000000000..ce9b73991 --- /dev/null +++ b/test/test_cpp23/pch.cpp @@ -0,0 +1,2 @@ +#include "pch.h" + diff --git a/test/test_cpp23/pch.h b/test/test_cpp23/pch.h new file mode 100644 index 000000000..3f722acbd --- /dev/null +++ b/test/test_cpp23/pch.h @@ -0,0 +1,10 @@ +#pragma once + +#pragma warning(4: 4458) // ensure we compile clean with this warning enabled + +#define WINRT_LEAN_AND_MEAN +#include "winrt/Windows.Foundation.h" +#include "winrt/Windows.Foundation.Collections.h" +#include "catch.hpp" + +using namespace std::literals; diff --git a/test/test_cpp23/test_cpp23.vcxproj b/test/test_cpp23/test_cpp23.vcxproj new file mode 100644 index 000000000..0577a2d6f --- /dev/null +++ b/test/test_cpp23/test_cpp23.vcxproj @@ -0,0 +1,239 @@ + + + + + Debug + ARM64 + + + Debug + Win32 + + + Release + ARM64 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {04E0D58C-4F4F-4A50-A1D0-EDCE1CB8E0EF} + unittests + test_cpp23 + 23 + stdcpplatest + + + + Application + true + v145 + + + Application + true + v145 + + + Application + false + true + v145 + + + Application + false + true + v145 + + + Application + true + v145 + + + Application + false + true + v145 + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + + + $(SolutionDir)_build\$(CppWinRTPlatform)\$(Configuration)\ + $(SolutionDir)_build\$(CppWinRTPlatform)\$(Configuration)\temp\$(MSBuildProjectName)\ + + + $(SolutionDir)_build\$(CppWinRTPlatform)\$(Configuration)\ + $(SolutionDir)_build\$(CppWinRTPlatform)\$(Configuration)\temp\$(MSBuildProjectName)\ + + + $(SolutionDir)_build\$(CppWinRTPlatform)\$(Configuration)\ + $(SolutionDir)_build\$(CppWinRTPlatform)\$(Configuration)\temp\$(MSBuildProjectName)\ + + + $(SolutionDir)_build\$(CppWinRTPlatform)\$(Configuration)\ + $(SolutionDir)_build\$(CppWinRTPlatform)\$(Configuration)\temp\$(MSBuildProjectName)\ + + + $(SolutionDir)_build\$(CppWinRTPlatform)\$(Configuration)\ + $(SolutionDir)_build\$(CppWinRTPlatform)\$(Configuration)\temp\$(MSBuildProjectName)\ + + + $(SolutionDir)_build\$(CppWinRTPlatform)\$(Configuration)\ + $(SolutionDir)_build\$(CppWinRTPlatform)\$(Configuration)\temp\$(MSBuildProjectName)\ + + + + Disabled + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreadedDebug + Level4 + true + %(AdditionalOptions) -flto -fwhole-program-vtables + stdcpplatest + + + Console + + + + + Disabled + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreadedDebug + Level4 + true + %(AdditionalOptions) -flto -fwhole-program-vtables + stdcpplatest + + + Console + + + + + Disabled + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreadedDebug + Level4 + true + %(AdditionalOptions) -flto -fwhole-program-vtables + stdcpplatest + + + Console + + + + + MaxSpeed + true + true + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreaded + Level4 + true + %(AdditionalOptions) -O3 -flto -fwhole-program-vtables + stdcpplatest + + + Console + true + true + + + + + MaxSpeed + true + true + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreaded + Level4 + true + %(AdditionalOptions) -O3 -flto -fwhole-program-vtables + stdcpplatest + + + Console + true + true + + + + + MaxSpeed + true + true + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreaded + Level4 + true + %(AdditionalOptions) -O3 -flto -fwhole-program-vtables + stdcpplatest + + + Console + true + true + + + + + + + + + NotUsing + + + Create + + + + + + \ No newline at end of file