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
C++ EH: initial front end work #5342
Conversation
3b9d6cf
to
8fc41b0
Compare
sc.func.flags |= flags; | ||
if (flags == (FUNCFLAGcppExceptions | FUNCFLAGdExceptions)) | ||
{ | ||
error("cannot mix catching D and C++ exceptions in the same function"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It has been pointed out to you there that it is a gratuitous restriction. You can e.g. just look at the language code for the exception to distinguish between them. Could you at least add a "yet" to the error message? That restriction unnecessarily convolutes the design from an user point of view.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've read it, and still don't understand why you need two personality functions. There is no technical difficulty in using the same for both. Take a look at Ada if you don't believe me.
http://www.adacore.com/adaanswers/gems/gem-114-ada-and-c-exceptions/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm afraid the Ada example says nothing whatsoever about what is going on under the hood, and so is not enlightening.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can e.g. just look at the language code for the exception to distinguish between them.
Of course, but that's only half the problem. The other half is the pointer in the TType table - a TypeInfo pointer needs to be distinguished from a C++ RTTI pointer. Elie suggests wrapping the C++ info in a TypeInfo. That may work for dmd, I have not investigated it completely yet. If it doesn't work, or is impractical, the other way to distinguish what kind of pointers are in TType is to use a different personality function that sets a flag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In C++ the TType value is a pointer to some rtti data. While I can accept being wrong, I always considered it to be:
- Found candidate (D/C++/other), get_ttype_entry_for it.
- If generic exception we are propagating is domestic (D exception class), proceed as usual.
- If both TType entry language and exception class hint at being C++, get the underlying exception type (cast exception to __cxa_exception*) and do pointer comparison with the TType value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could set aside some time to try it out in gdc and give feedback.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pointer comparison of the TType entries doesn't work, because you can catch the base class of the thrown type. This is true for both D and C++.
The exception class is NOT helpful in determining what types are caught. The only thing that tells what is in the TType is the personality function itself.
We could always invent our own LSDA format, but I'd rather not go that far.
3e924d6
to
c4944f3
Compare
Added code to emit the call to |
These are the ways to do it:
(4) is far and away the most straightforward, but it does come with the cost of not mixing RTTI and TypeInfo in the same function, which does not seem an egregious limitation to me. Elie's proposal (3) has some issues with where is the RTTI info defined - I don't want to wire RTTI info into dmd, I think it is more robust to regard them as opaque pointers. |
@WalterBright, where can I read, how do you plan to do that? AFAIR, if you want to catch |
I don't think that helps for in-flight routines. |
@@ -26,6 +26,7 @@ struct Target | |||
extern (C++) static __gshared int realpad; // 'padding' added to the CPU real size to bring it up to realsize | |||
extern (C++) static __gshared int realalignsize; // alignment for reals | |||
extern (C++) static __gshared bool reverseCppOverloads; // with dmc and cl, overloaded functions are grouped and in reverse order | |||
extern (C++) static __gshared bool cppExceptions; // set if catching C++ exceptions is supported |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also target.h. :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@WalterBright: If you want to go for the "simple" design (as the others pointed out, I'm not sure if it is actually simpler since you need to at least mangle and reference the type info anyway), couldn't you just use any of the usual tricks to steal a bit from the type pointer to encode the C++/D distinction? |
Actually what I suggested is more like (1). To avoid meddling with TypeInfo while making the distinction possible I simply wrapped the type_info pointers inside a small D class: class __cpp_type_info_ptr {
type_info *p;
} Then If you plan to use |
Shouldn't be a problem since we already do C++ mangling.
I prefer to avoid such, as they play hell with things that try to analyze memory usage (like GCs). |
@Syniurge thanks for helping with this. It is indeed a good idea you have, better than my wrapping idea and better than David's pointer bit idea. It does have a cost of an extra dynamic cast for each catch clause checked, though that is unlikely to be much of a slowdown considering all the other code the personality routine executes. I plan on using We still need to exhort people to stop using D exceptions as a normal flow-of-control mechanism. I'm looking at you, |
My point exactly.
In this case the table is static, refers to global symbols, and wouldn't even be decoded by any of the usual tools/GCs anyway. In any case, I'm not trying to suggest that you should go for the quick hack (especially since you might need to get a bit creative with relocations). I'm just arguing that there is no reason to try and push in a half-baked implementation that is more complex than necessary because it contains gratuitous restrictions. |
?? |
@WalterBright: @Syniurge is Ellie from the forums (and of Calypso fame), and his implementation is what we have been suggesting from the beginning. |
That's a line comment on the explicit |
@klickverbot Actually, the alternate personality entry point is the simplest of all the proposals here. It would also be the fastest and smallest method - set a flag and then call a common
|
Ok, I understood. We should use BTW, the similar issue: can we perform dynamic casting for extern(C++) classes via the same method?
Of course, we should able to get c++ |
@IgorStepanov - that is unrelated here I think. I'd suggest raising a bug report if you think that's a problem. |
OT
We have to rewrite the whole module b/c it must become @nogc to be used for stacktraces. |
5f0852b
to
427fc82
Compare
I finished the initial implementation in the compiler. Decided to go with Elie's approach, though still one cannot mix catching C++ and D exceptions in the same try-catch, because I didn't want the generated code to require the existence of C++ runtime libraries unless C++ exceptions were actually in the code. Once this passes the autotester, it's on to the Phobos support! |
final const(char)* mangle_typeinfo(Dsymbol s) | ||
{ | ||
buf.writestring("_ZTI"); | ||
source_name(s); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be cpp_mangle_name(s, false)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or at the very least be able to handle namespaces in the same way.
FYI, I've got it working without needing |
Is it correct to compare two type_info pointers instead if __do_catch call? |
We don't generate C++ typeinfo, how on earth do you expect this to work? |
I expect that we can catch only those C++ types which are defined in C++ code. Now we need to define in D extern(C++) type_info interface, which declares
This is the most strange moment, where we need to define a correct D binding for After that we should call __do_catch instead of pointer comparsion:
|
I don't want druntime to depend on libstdc++. That is quite out the question. |
extern reference to the typeinfo generated by C++. If you're throwing C++ exceptions, it is reasonable to expect linking to libstdc++, and the C++ compiler will generate the typeinfo.
Should be doable since the only references are to std::type_info, and they are via virtual functions. |
There is no dependence in my code. Interface is only interface, |
I gave it a go an it seems to work without quarrel. However:
Direct comparison becomes a call to:
|
It may be "deleting destructor" (D0) and "complete object destructor" (D1). AFAIK, C++ compilers generates more then one destructors for the one class.
Do you allow to catch pointers? And maybe you should do this casting after
|
I've got it working now. Will clean it up and prepare a PR. |
0ebfdd5
to
03e6caa
Compare
This will fail until dlang/druntime#1470 is pulled. |
version (linux) | ||
{ | ||
version (X86_64) | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indents?
8625c71
to
2b80b70
Compare
Auto-merge toggled on |
C++ EH: initial front end work
This should do it for the front end.