-
Notifications
You must be signed in to change notification settings - Fork 12.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ms] __LPREFIX feature of MSVC isn't supported in clang #27402
Comments
I've noticed that MSVC somehow even translates The code I'm looking at is similar to: #define LOGMESSAGE(text) _T(__FUNCTION__) _T(":") text Result after preprocessing becomes: __LPREFIX( __FUNCTION__) L":" "some text" However, if I try to reproduce this in a small example, I don't get this behavior. Replacing the |
It would be good to find some documentation for that, I can't find anything online. |
CC @EugeneZelenko FYI we now have |
@Endilll: Thank you for information! |
To avoid duplicate work, I am working at this issue (in my branch). |
In terms of this issue I am trying to add support for the following expressions in Clang (under MSVC compatibility mode): https://godbolt.org/z/nrj1j3bMY #define _CONCAT(A, B) A##B
#define CONCAT(A, B) _CONCAT(A, B)
int main() {
const char *x = __lPREFIX(L"Yes, " __LPREFIX(u8"it " __lPREFIX(U"is ")) L"insane function " CONCAT(L, __FUNCTION__));
return 0;
} I see the following levels of inseparable implementation:
I think the implementation is inseparable, because: if (1) is implemented, then we need to handle I am writing this message, because I see difficulty at combination of (2,3,4), and (as per my current plan) it would require significant changes in Sema, by either adding new type of Expr in Clang, or reworking 1. Preprocessor. As per my observations and experiments with MSVC, /// L##__FSTREXP __FUNCTION__
/// || | |
/// vv v v
/// __LPREFIX( __FUNCTION__) All of these transformations are easily made in 2, 3, 4. Sema and TemplateInstantiator. Unfortunately, the approach we followed in D153914, was erroneous: https://godbolt.org/z/vx9zY8aTj template<class T> class A {
public:
A() {
static const char *X = __FUNCTION__; // A<class int>::A
static const char *Y = "" __FUNCTION__; // A::A<T>
}
};
int main() {
A<int> a;
} And thus we cannot blindly implement (2, 3) without taking (4) into account. An example of partial implementation is in lprefix. My proposal for (2,3,4). Create a new kind of Pinging reviewers of D153914: @AaronBallman, @cor3ntin, @tahonermann Edit: regarding the name of new Expr class. Taking a look at existing classes, I think a good name would be like |
tl;dr I wanted to add yet another AST node Recently I've learned that
constexpr size_t operator""_len(const char*, size_t len) { return len; }
constexpr size_t operator""_len(const char8_t*, size_t len) { return len; }
constexpr size_t operator""_len(const char16_t*, size_t len) { return len; }
constexpr size_t operator""_len(const char32_t*, size_t len) { return len; }
constexpr size_t operator""_len(const wchar_t*, size_t len) { return len; }
size_t foo() {
return __lPREFIX(__UPREFIX(__LPREFIX(U"wtf"_len) L"qwe" __LPREFIX(__FUNCTION__))) ""_len;
}
https://godbolt.org/z/PrY3cMWMP #include <cstddef>
constexpr size_t operator""_len(const char*, size_t len) {
return len;
}
size_t foo() {
return ""_len "333"_len * "2"_len "2"_len - ""_len "6" "6"_len "6" "666"_len;
} The latest implementation plan looks as follows: we can scan the whole "string literal" (including string-like predefined macros like On template instantiation phase we can re-build Update: I didn't have much time to work on this until now. I am still interested in finishing this task. I'll try to make it until LLVM 19 release. |
Currently I have implemented transformation of string-prefixes ( // In this example macros are defined in reverse order to be able to read from top to bottom.
STR2(__FUNCTION__);
#define STR2(A) #A STR1(A) // Would get expanded to: "__FUNCTION__" STR1(__FSTREXP __FUNCTION__)
#define STR1(A) #A // Would get expanded to: "__FUNCTION__" "__FSTREXP __FUNCTION__" WIDE(__FUNCTION__)
#define WIDE(X) _WIDE(X)
#define _WIDE(X) L##X
/*
WIDE( __FUNCTION__)
|
/|
/ |
/ |
/ |
v v
_WIDE(__FSTREXP __FUNCTION__)
L##__FSTREXP __FUNCTION__
|| | |
vv v v
__LPREFIX( __FUNCTION__)
*/ Now I am at the point of implementing semantics of U"Hello" __UPREFIX(L" " "World") The concatenation of See https://godbolt.org/z/hcc8KGf5e Another difficulty is that I didn't take this into account when I implemented 66c43fb, The support of such behavior I want to implement by introducing a new AST node (as mentioned above) called See https://godbolt.org/z/qhqr5Gsbx Implementation decision 1Due to all of above I see several possible implementations (disclaimer, where I write "recursive" I mean unrolled recursion using some container; I am aware that Clang does not welcome recursion in parsers):
I am inclining towards the last option, because: pure string literal parser would not need to know about Microsoft specific stuff, and thus it would be easier to maintain it. Regarding
Implementation decision 2There are two ways in regards to handing template dependent context for
I didn't decide which is better yet. |
CC @cor3ntin ^ |
Regarding "implementation decision 1": I was concerned that I should rather follow (1) and embed
|
Thank you for the detailed investigation into improved compatibility here! It was clearly a lot of work and it is truly appreciated. That said, I have some concerns with how much effort we would still need to put into this feature, and the long term maintenance costs for something that would not be used a lot. It's not a documented API from Microsoft, it isn't used in any Windows SDK, MS CRT, or other system headers (that I've been able to find, anyway), and it's not commonly used in the wild (at least with the best tools we have to search over a large corpus of code: https://sourcegraph.com/search?q=context:global+__LPREFIX+lang:C+lang:C%2B%2B&patternType=keyword&case=yes&sm=0). So this looks like a very large amount of implementation effort for a nominal feature. This topic has come up before in https://bugs.llvm.org/show_bug.cgi?id=11789 and I think we ended up with the amount of support we'd like in 3a691a3 (patch discussion found at https://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20120618/059525.html). In short, we don't support I think we may want to close this issue as Won't Fix given how much effort is required for exact MS compatibility and how little use this extension seems to have in the wild. If it starts showing up in system headers, we may want to reconsider at that point. |
tl;dr I am willing to take a risk that my patch could not end up in main. Thank you for feedback and references! I understand your concerns regarding maintenance cost, and amount of efforts required to develop such support. Some contextThe main reason I started working at this issue is that the product of my employer would benefit from such support. Initially I worked at it once a workweek, however currently I have more important tasks, so now I allocate a few hours on weekends towards this issue, mainly because of combined interests: the commercial product of my employer as well as this could be useful for community of LLVM. That's why it takes me a long time (the same problem was with msvc::constexpr which took me a year to merge into main). I hope in future I could allocate more time towards LLVM during workweek.Why is it important for our commercial product? Keeping it short, Clang cannot parse a source file that was preprocessed by MSVC, if it contains More contextWe have workarounds, and we are planning to switch to using my patch that supports __LPREFIX in the AST, but the patch misses semantics for it. I am sure LLVM community won't be interested in such a patch (similarly to no-op C++11 attributes). So, ultimately, the goal would be to upstream the maintenance cost, I believe it's a win-win situation: Clang gets __LPREFIX support, my employer upstreams maintenance cost, I get "internet points".Why is it important for Clang? Clang-cl is not able to produce similar results as MSVC when There are ways to make it work, but this would add even more workarounds to existing workaround approach with Where I would like to finish this task, and I am willing to take a risk of getting merge rejection, if community don't like the final patch series. At the moment I see the final result as series of several patches:
I believe (2) and (3) should not be difficult, I just need to come up with a proper implementation. I am open for discussions if someone has interest in collaboration. And I could create a more detailed development plan (instead of keeping everything in my unstructured notes and thoughts) if someone would find it useful. |
My plans have changed. I don't have time to work on it either at work or during my free time. I'll try to get back to it during the next half of the year. Edit: Maybe I'll return to this sometime in the first half of 2025. |
Extended Description
This report is about MSVC feature
__LPREFIX
that adds prefixL
to its argument, for example, it changes its argument's typechar[n]
towchar_t[n]
. Identifier__LPREFIX
with any argument is unknown for clang.=========Environment=============
OS: Win
Version: trunk
=========Reproducer==============
test.cpp
===========Output================
MSVC compiles clearly
It should work like macro, but it is really not preprocessor macro:
$ cl -E test.cpp
=================================
Andrey Skripkin
Software Engineer
Intel Compiler Team
The text was updated successfully, but these errors were encountered: