-
-
Notifications
You must be signed in to change notification settings - Fork 609
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
frontend: add support for __MANGLED_FUNCTION__ special keyword #12252
Conversation
|
Thanks for your pull request and interest in making D better, @ljmf00! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please see CONTRIBUTING.md for more information. If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment. Bugzilla referencesYour PR doesn't reference any Bugzilla issue. If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog. Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub run digger -- build "master + dmd#12252" |
60f8d1d to
4aa76b9
Compare
|
What's the use case? |
That's problematic when Imagine this situation: void main()
{
int foo()
{
mixin(__FUNCTION__).mangleof.writeln;
return 1;
}
foo();
} |
Signed-off-by: Luís Ferreira <contact@lsferreira.net>
Signed-off-by: Luís Ferreira <contact@lsferreira.net>
Signed-off-by: Luís Ferreira <contact@lsferreira.net>
Signed-off-by: Luís Ferreira <contact@lsferreira.net>
Signed-off-by: Luís Ferreira <contact@lsferreira.net>
4aa76b9 to
a5d2fa2
Compare
I'm not sure what you mean here |
I meant, an alternative would be using With So I don't see any alternative that can totally substitute |
You want the return type, right, but in this case in the nested function you have it with Also needs a test of C++ mangling probably (haven't played with it yet) |
Yeah, on discord I wanted the mangled name but not sure if it's the best way to get the return type as a string, although, this could be easily added to the runtime demangler anyway. The easiest way to do it would be to get it from I didn't want to show that case here, because it was very specific and it might not fit here. There's a way to get a mangled function from I know, the end-user shouldn't generally depend on the mangled name, like parsing it or something, but this could be useful for other things like doing something that externally interfaces with the D ABI. |
"It could be useful" really doesn't meet the burden of proof for an addition to the language. |
|
Using auto stuff(...)()
{
// need foo's return type here
// to do some fancy stuff
// and return the appropriate type
}
void main()
{
int fooInt()
{
return stuff();
}
float fooFloat()
{
return stuff();
}
}It would be possible to obtain the return type "directly" if both functions were declared in the global scope, however neither |
I didn't had a concrete example, but let see, the case I presented, externally interface with the D ABI. Currently, there's no feasible way to get the mangled name. Mangling is useful in the user perspective for various reasons ranging from logging mangled names for debugging purposes to dynamically loading certainly used D symbols externally with Internally, the D profiler logs the mangled symbols to a file for possible usage by a viewer but the user can't do that. Maybe the biggest things you can have with it is instrumentation, like you do with If we look to other compilers like C++, although it's not a standard across all compilers, MSVC as
Depending on the runtime for this is not optimal. The worst thing we have on D is depending on the runtime for reasonable basic functionality. I'm not against other implementations, but rather about your solution.
void main()
{
int foo()
{
mixin(__FUNCTION__).mangleof.writeln;
return 1;
}
foo();
} |
Surely the alternative to depending on the runtime in this case is just writing your own demangler anyway? |
No that's not the point here. You can use the runtime demangler externally, and not on the user application that uses |
For you, it's not a problem, but for a lot of people that don't want to depend on the actual runtime code or want to have a minimal runtime for whatever reason, it is. @FFY00 is an example of an embedded developer in D. In fact, the current runtime implementation doesn't even work with CTFE, AFAIK. // dmd -defaultlib= app.d
extern(C) void _d_dso_registry() {}
extern(C) pragma(printf) int printf(scope const char* format, scope const ...);
extern(C) void main()
{
import core.demangle : demangle;
printf("%s", (demangle("_D7example12__ModuleInfoZ") ~ '\0').ptr);
}I guess this is basically because
That doesn't solve the problem again. If you want to use it as a default argument, the user needs to specifically use the trait instead. I can show you another example that you can't do with the current traits, plus, bear in mind that traits can't evaluate strings nor using mixins to transform the strings to symbols for nested functions. template bar(string mfunc = __MANGLED_FUNCTION__)
{
auto bar()
{
return mfunc;
}
}
void main()
{
int foo()
{
bar!();
// pragma(msg, bar!());
return 1;
}
}Tell me how you can do instrumentation without explicitly pass the symbol or using a
Your example is using the actual symbol, Show me an example of how you can get the mangling without the demangler runtime and by using plain strings, if you want, like
Once again, you are dependent on the symbol. You can't pass the symbol implicitly as you do with
?? That's pointless. Instrumentation is about, for example, logging the mangled symbol on runtime function calls., like you do on the compiler profiler. Parsing the binary is either complex, tedious and doesn't fit here, anyway. See more about applications of instrumentation here: https://en.wikipedia.org/wiki/Instrumentation_(computer_programming)#Output
I proved to you that currently, CTFE does nothing to the current runtime implementation. And already talked about that above.
I can investigate more about it. I guess it's possible to do it but needs another semantic stage. |
sigh This is how you run people out of your language. I have spent a lot of time and effort over the years trying to give D a real try for proper projects, I also spent a significant amount of time trying to fix some of the issues I was running into, but I gave up after consistently running up into issues like this and receiving this kind of friction trying to do anything. Every time I try to come back I run into the same kind of stuff... It's honestly very demotivating. This problem is fairly simple. I want a mangled version of As of now, you failed to provide any real solution.
No, I actually need to call the mangler. But neither of the variants available, And other big issue, where in the spec does it guarantee that what you propose will be CTFE-ed? Let's take a simple example. extern(C) pragma(printf) int printf(scope const char* format, scope const ...);
extern(C) void main()
{
auto foo(immutable(char)* caller = (__MANGLED_FUNCTION__ ~ '\0').ptr)
{
printf("%s\n", caller);
}
foo();
}Please show me how I can do that in a way that the spec guarantees will happen at compile time.
Why is there |
I haven't seen all the discussion so risk sounding like a broken record. But... |
For cross language binary interfaces, this is what you have Another alternative is |
We are aware, but that does not negate this. It is merely an alternative for some situations. |
You can check if the |
Yes it does if the intent is to call from another language, as |
Yes, although, that shouldn't impossibilitate the user to do it, plus instrumentation doesn't necessarily need to deal with interfacing. |
It does if you don't provide any flag, but the code example you gave is not correct. If you want something to be CTFEd, you need to assign it to a variable that is A more correct example would be: extern(C) void _d_dso_registry() {}
extern(C) pragma(printf) int printf(scope const char* format, scope const ...);
import core.demangle : demangle;
immutable Mangling = demangle("_D7example12__ModuleInfoZ");
extern(C) void main()
{
printf("%.*s", (cast(int) Mangling.length), Mangling.ptr);
}Now there is a bug here: It seems that DMD chokes on exceptions in CTFE code with
From the rest of your post, it seems you want to be able to pass it as a default argument, which is why you went with implementing it as a token ? |
Exactly! I find no other way to do that without a token like that. If there is, it would be great. Also, the problem about This forward reference problem is, right now, happening on |
|
@FFY00 :
Just to be clear here, I'm not trying to gatekeep here. I, and I'm sure other contributors, would really like to understand why D is currently not fitting your use case. But it seems that we're missing a piece of the story, as a conversation happened on Discord, and it seems that now, people are fixating on this approach as being the only possible alternative. It might be true, but the proposer needs to make a case for it. This PR was created without any explanation as to its use case, and why the established alternatives are not working. That's why you are seeing pushback.
The easy way is to make it a template argument. To force the caller to CTFE the default argument, I currently can't think of anything else that would work with tokens.
Something like: void logCaller (string mangledName = __traits(getCurrentSymbol).mangleof)
{
}Provided that the default argument is correctly evaluated in the caller's context, this would work without special case, and be useful for other people as well. However, if your use case is instrumentation, there are other approaches that work, too. Other profilers, such as tracy, will just use the stack trace for that. We have bindings for LLVM's libunwind in druntime (https://github.com/dlang/druntime/blob/master/src/core/internal/backtrace/libunwind.d) which you might want to look into (that's what I was getting at with my "parse the binary" approach, sometimes a runtime approach is the best option). |
From our limited interactions, you are one of the few people that hasn't been doing this, but most of the people are often dismissive, which you can even see on this thread, being it intentional or not. At this point I can't be assuming good faith on everything because this happens so much.
I was not part of that conversation, I have been simply trying to make a point for this use-case here. I am not fixated on this approach, but it does seem like the clear obvious to me -- see my reply below.
The use-case is pretty self-explanatory, easily accessing the mangled name of the current function.
Again, embedded, I am working with limited space, so I am not templating a big function because of this. That is purely a work around that happens to work on desktop because you don't care about the object size, it is an incorrect approach to the problem -- the code is the same, I should not be forced to make multiple copies of it. When you start sacrificing correctness "because this way works", you are most likely dismissing use-cases, because "your way" that wasn't supposed to be used for this will a lot of the times not translate to other situations. This is generally what I think has been going wrong with D and its unfitness to be practically used for embedded development and other not-desktop use cases.
Again, why is there a |
Building on this, I think what would actually be useful would be __traits(getSymbol, __MANGLED_FUNCTION__)Instead of making it only able to get the symbol in the current context. |
I think you're underestimating how difficult this is. I wouldn't know with what strategy dmd could infer a return type for this: auto foo() {
mixin(crazyCodeGeneratingTemplate!__MANGLED_FUNCTION__);
}But I'll be happy if you could make it work. |
That's not a use-case, just a description of what it does. It's like saying "the use case for I can sort of kind of see what this can be used for and can relate to why workarounds are unsatisfactory, but still have a hard time picturing how this would be used concretely in an actual project, so a specific complete example could be useful here. |
I wonder if this old PR allowed to get the right mangle, |
Thanks for the compliment, but, and I'm sure you already know this, not assuming good faith isn't a workable basis to have a conversation on the merit's of an open source contribution. And that goes both ways, obviously, reviewers have to assume good faith from the contributors.
As mentioned by @dkorpel , it's not a use case as much as it is a specific approach to a use case. And since there were a few use cases being mixed up (that discussion on Discord, your own, potentially others?), the conversation got quite confusing IMHO.
I agree, and I think it should work. I'm not even saying it's a good workaround. What I wanted to point out was that we needed to understand the use case, what work, and what didn't, to find the best fix that would fit within the big picture that D has.
To be clear, I (or any other reviewers) could just merge this PR, as it's fairly simple and @ljmf00 has been perfectly following the contributions guidelines (BTW: thanks for the quality of your contributions, past and present). Then we call it a day. So when there's a PR trying to introduce a new feature, my first question will always be "What's the use case?", so that we can be sure that the language actually is what you need it to be, not only what you ask it to be.
I believe it is because
There's a few that do. They take
The reason is likely historical: Tokens were implemented in D1, |
For a non-nested function, this works: int foo() {
__traits(parent, {}).mangleof.writeln;
return 1;
}If it's nested, however, we get this error: So, as I see it, there's a workaround for non-nested functions right now, and the example given wouldn't work with a |
I still assume good faith in the interactions themselves, just not in the silent dismissal of certain points. Me assuming that "they just forgot" and not pressing for the points to be addressed, like I did here, is exactly what drove me out of the community.
Sure. If you want a proper use-case I have, I want to cache some things based on the caller, this is helpful for embedded development. I can do this no problem with C, the names are not mangled, so I can use
That is fine then, if you think introducing this in traits is the correct approach, go for it. It just wasn't to me from the context I had. Also, please note that my original comment was a reply to you telling us to use
I thought
Okay, that makes sense.
Shouldn't the current tokens be added as traits and marked for removal in a future version then?
I share this opinion, I had actually written this in my previous reply but choose to remove it. |
Yeah. The conversation on Discord kinda deviates from the usefulness of this approach. I understand that people without the context may feel a bit confused and I miss some rationale here.
Yes. I don't think DMD can do it right now. I can give an error if some forward reference occurs in that situation.
I've been looking for that. I've seen one thing there that could lead to inconsistency with the current approach, using tokens.
Thanks. Appreciate :) Ok. I guess we are getting somewhere with this. Now, I totally understand your point here. This case could introduce more complexity and keep the same old problem about getting the raw symbol. Maybe a good approach is to use traits and getting rid of those tokens, except, essential ones like
This makes even more sense. I didn't think that this came from D1, tho. Removing |
|
The ghost user contacted me via email. If you want to come up with his idea on #11538 , I can rebase it and work from those commits with the original authorshipp. I can ask him/her some context too. |
|
Is this still being pursued? |
I don't think so. This will eventually be superseded by the proposed |
|
Okay, then I'll close it for now in favor of someone rebooting #11538 |
Signed-off-by: Luís Ferreira contact@lsferreira.net
This may need changes on the spec before the merge.
CC: @maxhaton