Skip to content

Fix: TraceLoggingDynamic.h failing under /Zc:preprocessor on msvc#80

Merged
Robo210 merged 3 commits intomicrosoft:mainfrom
cgettys-microsoft:main
Jan 20, 2026
Merged

Fix: TraceLoggingDynamic.h failing under /Zc:preprocessor on msvc#80
Robo210 merged 3 commits intomicrosoft:mainfrom
cgettys-microsoft:main

Conversation

@cgettys-microsoft
Copy link
Contributor

@cgettys-microsoft cgettys-microsoft commented Jan 15, 2026

  • Replace the non-conformant L#exp and L##str with #exp and #str, since there is already a proceeding string literal that they will be combined with; per https://learn.microsoft.com/en-us/cpp/preprocessor/preprocessor-experimental-overview?view=msvc-170#lval, as well as via Compiler Explorer , this should compile with both the old and new preprocessor (as well as being more compatible with clang, gcc, and so on.
  • Also replace the parentheses shenanigans (that really shouldn't compile!) with immediately evaluated Lambda shenanigans that are conformant preprocessor compatible. I'm assuming TraceLoggingDynamic.h already requires C++11, but if it doesn't, we could make TLD_DEBUG default to 0 for pre-C++11 compiler versions.

Closes #79

@Robo210 Robo210 requested a review from idigdoug January 15, 2026 06:20
#ifndef _tld_ASSERT
#if TLD_DEBUG
#define _tld_ASSERT(exp, str) ((void)(!(exp) ? (__annotation(L"Debug", L"AssertFail", L"TraceLogging: " L#exp L" : " L##str), DbgRaiseAssertionFailure(), 0) : 0))
#define _tld_ASSERT(exp, str) ((void)(!(exp) ? (__annotation(L"Debug", L"AssertFail", L"TraceLogging: " #exp L" : " #str), DbgRaiseAssertionFailure(), 0) : 0))
Copy link
Contributor Author

@cgettys-microsoft cgettys-microsoft Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure which widening trick is most portable outside msvc.
https://learn.microsoft.com/en-us/cpp/preprocessor/preprocessor-experimental-overview?view=msvc-170#lval
suggests something like 3 options.

#define WIDE(str) L##str
#define STRING2(str) WIDE(#str)

Might be more robust than this to older compilers? but I'm not sure how much of a concern that is given the current non-conformance of the header.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to use a different one if you have preferences.

#ifndef _tld_ASSERT
#if TLD_DEBUG
#define _tld_ASSERT(exp, str) ((void)(!(exp) ? (__annotation(L"Debug", L"AssertFail", L"TraceLogging: " L#exp L" : " L##str), DbgRaiseAssertionFailure(), 0) : 0))
#define _tld_ASSERT(exp, str) ((void)(!(exp) ? (__annotation(L"Debug", L"AssertFail", L"TraceLogging: " #exp L" : " #str), DbgRaiseAssertionFailure(), 0) : 0))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the L seems reasonable. Why did we also change the str from "prefix with L" to "convert to string"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tl;dr: because I screwed up.

I'll be honest, I'm not a macro or preprocessor wizard. I'm just tilting at windmills over here experimenting with seeing if we could maybe possibly get a large, 1st party codebase (cough SQL cough) to use header units instead of PCH, so that we can enter this decade.

So human error on my part. I saw many, many places where macros like L##x were not playing nice because the old preprocessor was happy to pretend they actually just were L x.
Some of those also had evaluation order shenanigans going on... sometimes it seems like the old preprocessor likes to treat

`MY_MACRO((X))

As if it was:

#define DEFER(...) __VA_ARGS__
MY_MACRO(DEFER(X))

Though I could be wrong about that, I've spent the last two days traipsing my way through ~300 files full of particularly cursed macros.

And I hadn't had any problems with TraceLoggingProvider.h, so I hadn't spotted the similarity.

Copy link
Collaborator

@idigdoug idigdoug left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless there was a reason to change the behavior, please change #str to str to preserve existing behavior.

Comparable code in TraceLoggingProvider.h looks like this:

  #define _tlg_ASSERT(exp, str) ((void)(!(exp) ? (__annotation(L"Debug", L"AssertFail", L"TraceLogging: " _tlg_LSTRINGIZE(exp) L" : " str), TLG_RAISEASSERTIONFAILURE(), 0) : 0))

@cgettys-microsoft
Copy link
Contributor Author

Unless there was a reason to change the behavior, please change #str to str to preserve existing behavior.

Comparable code in TraceLoggingProvider.h looks like this:

  #define _tlg_ASSERT(exp, str) ((void)(!(exp) ? (__annotation(L"Debug", L"AssertFail", L"TraceLogging: " _tlg_LSTRINGIZE(exp) L" : " str), TLG_RAISEASSERTIONFAILURE(), 0) : 0))

Done, good catch.

An aside on TraceLoggingProvider.h - it's probably academic (since I assume that's usually only ever compiled with gcc and clang and the like, and I also assume the macros in question don't expect to be passed zero varadiac arguments. But the old msvc preprocessor is lax about comma elision around variadic arguments - other compilers will only elide , ## __VA_ARGS__ to nothing if there are no variadic arguments, but the old msvc preprocessor would also elide , __VA_ARGS__:
https://learn.microsoft.com/en-us/cpp/preprocessor/preprocessor-experimental-overview?view=msvc-170#comma-elision-in-variadic-macros

Thought I'd mention it just in case.

@Robo210 Robo210 merged commit 6216382 into microsoft:main Jan 20, 2026
1 check passed
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.

TraceLoggingDynamic.h is not MSVC conformant preprocessor compliant

3 participants