Skip to content

Commit cea2e41

Browse files
authored
Add std::source_location support when logging error information (#1185)
1 parent 129fade commit cea2e41

File tree

8 files changed

+176
-77
lines changed

8 files changed

+176
-77
lines changed

strings/base_error.h

Lines changed: 91 additions & 75 deletions
Large diffs are not rendered by default.

strings/base_includes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
#include <format>
2929
#endif
3030

31+
#ifdef __cpp_lib_source_location
32+
#include <source_location>
33+
#endif
34+
3135
#ifdef __cpp_lib_coroutine
3236

3337
#include <coroutine>

strings/base_macros.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,27 @@
5454
struct IUnknown;
5555
typedef struct _GUID GUID;
5656
#endif
57+
58+
// std::source_location is a C++20 feature, which is above the C++17 feature floor for cppwinrt. The source location needs
59+
// to be the calling code, not cppwinrt itself, so that it is useful to developers building on top of this library. As a
60+
// result any public-facing method that can result in an error needs a default-constructed source_location argument. Because
61+
// this type does not exist in C++17 we need to use a macro to optionally add parameters and forwarding wherever appropriate.
62+
#ifdef __cpp_lib_source_location
63+
#define WINRT_IMPL_SOURCE_LOCATION_ARGS_NO_DEFAULT , std::source_location const& sourceInformation
64+
#define WINRT_IMPL_SOURCE_LOCATION_ARGS , std::source_location const& sourceInformation = std::source_location::current()
65+
#define WINRT_IMPL_SOURCE_LOCATION_ARGS_SINGLE_PARAM std::source_location const& sourceInformation = std::source_location::current()
66+
67+
#define WINRT_IMPL_SOURCE_LOCATION_FORWARD , sourceInformation
68+
#define WINRT_IMPL_SOURCE_LOCATION_FORWARD_SINGLE_PARAM sourceInformation
69+
70+
#pragma detect_mismatch("WINRT_SOURCE_LOCATION", "true")
71+
#else
72+
#define WINRT_IMPL_SOURCE_LOCATION_ARGS_NO_DEFAULT
73+
#define WINRT_IMPL_SOURCE_LOCATION_ARGS
74+
#define WINRT_IMPL_SOURCE_LOCATION_ARGS_SINGLE_PARAM
75+
76+
#define WINRT_IMPL_SOURCE_LOCATION_FORWARD
77+
#define WINRT_IMPL_SOURCE_LOCATION_FORWARD_SINGLE_PARAM
78+
79+
#pragma detect_mismatch("WINRT_SOURCE_LOCATION", "false")
80+
#endif

strings/base_meta.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
WINRT_EXPORT namespace winrt
33
{
4-
hresult check_hresult(hresult const result);
4+
hresult check_hresult(hresult const result WINRT_IMPL_SOURCE_LOCATION_ARGS);
55
hresult to_hresult() noexcept;
66

77
template <typename D, typename I>

test/test/custom_error.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,11 @@ namespace
5959

6060
void __stdcall logger(uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept
6161
{
62-
lineNumber; fileName; functionName;
62+
// In C++17 these fields cannot be filled in so they are expected to be empty.
63+
REQUIRE(lineNumber == 0);
64+
REQUIRE(fileName == nullptr);
65+
REQUIRE(functionName == nullptr);
66+
6367
REQUIRE(returnAddress);
6468
REQUIRE(result == 0x80000018); // E_ILLEGAL_DELEGATE_ASSIGNMENT)
6569
s_loggerCalled = true;

test/test_cpp20/custom_error.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include "pch.h"
2+
3+
using namespace winrt;
4+
using namespace Windows::Foundation;
5+
6+
namespace
7+
{
8+
static bool s_loggerCalled = false;
9+
10+
// Note that we are checking that the source line number matches expectations. If lines above this are changed
11+
// then this value needs to change as well.
12+
void FailOnLine15()
13+
{
14+
// Validate that handler translated exception
15+
REQUIRE_THROWS_AS(check_hresult(0x80000018), hresult_illegal_delegate_assignment);
16+
}
17+
18+
void __stdcall logger(uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept
19+
{
20+
// In C++20 these fields should be filled in by std::source_location
21+
REQUIRE(lineNumber == 15);
22+
const auto fileNameSv = std::string_view(fileName);
23+
REQUIRE(!fileNameSv.empty());
24+
REQUIRE(fileNameSv.find("custom_error.cpp") != std::string::npos);
25+
const auto functionNameSv = std::string_view(functionName);
26+
REQUIRE(!functionNameSv.empty());
27+
REQUIRE(functionNameSv == "FailOnLine15");
28+
29+
REQUIRE(returnAddress);
30+
REQUIRE(result == 0x80000018); // E_ILLEGAL_DELEGATE_ASSIGNMENT)
31+
s_loggerCalled = true;
32+
}
33+
}
34+
35+
TEST_CASE("custom_error_logger")
36+
{
37+
// Set up global handler
38+
REQUIRE(!s_loggerCalled);
39+
REQUIRE(!winrt_throw_hresult_handler);
40+
winrt_throw_hresult_handler = logger;
41+
42+
FailOnLine15();
43+
REQUIRE(s_loggerCalled);
44+
45+
// Remove global handler
46+
winrt_throw_hresult_handler = nullptr;
47+
s_loggerCalled = false;
48+
}

test/test_cpp20/pch.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,6 @@
1111
#include <winstring.h>
1212
#include "catch.hpp"
1313

14+
#include <string_view>
15+
1416
using namespace std::literals;

test/test_cpp20/test_cpp20.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@
281281
</ItemGroup>
282282
<ItemGroup>
283283
<ClCompile Include="await_completed.cpp" />
284+
<ClCompile Include="custom_error.cpp" />
284285
<ClCompile Include="format.cpp" />
285286
<ClCompile Include="hstring.cpp" />
286287
<ClCompile Include="main.cpp">

0 commit comments

Comments
 (0)