This repository was archived by the owner on Feb 8, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 19
add test for catching D exceptions from C++ on Win32 #15
Open
rainers
wants to merge
1
commit into
ldc-developers:ldc
Choose a base branch
from
rainers:cxx_catch_dexceptions
base: ldc
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| // D exceptions to be caught by C++ | ||
|
|
||
| #pragma once | ||
|
|
||
| namespace D { | ||
|
|
||
| struct string | ||
| { | ||
| size_t length; | ||
| const char* ptr; | ||
| }; | ||
|
|
||
| class Object; | ||
|
|
||
| extern "C" { | ||
| string _d_toString(Object* o); | ||
| } | ||
|
|
||
| class Object | ||
| { | ||
| void* __monitor; | ||
|
|
||
| virtual void _classinfo_data() = 0; | ||
|
|
||
| protected: | ||
| // don't call directly, ABI mismatch | ||
| virtual string _toString(); | ||
| virtual size_t _toHash(); | ||
| virtual int _opCmp(Object* o); | ||
| virtual bool _opEquals(Object* o); | ||
|
|
||
| public: | ||
| string toString() { return _d_toString(this); } | ||
| }; | ||
|
|
||
| class Throwable : public Object | ||
| { | ||
| public: | ||
| string msg; /// A message describing the error. | ||
|
|
||
| /** | ||
| * The _file name and line number of the D source code corresponding with | ||
| * where the error was thrown from. | ||
| */ | ||
| string file; | ||
| size_t line; /// ditto | ||
|
|
||
| void* info; | ||
| Throwable* next; | ||
|
|
||
| virtual string _toString(); | ||
| }; | ||
|
|
||
| class Exception : public Throwable | ||
| { | ||
| }; | ||
|
|
||
| class Error : public Throwable | ||
| { | ||
| Throwable* bypassedException; | ||
| }; | ||
|
|
||
| } // namespace D | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| #include "dexcept.h" | ||
| #include <string.h> | ||
| #include <assert.h> | ||
|
|
||
| void throwException(); | ||
|
|
||
| bool test_eh() | ||
| { | ||
| try | ||
| { | ||
| throwException(); | ||
| } | ||
| catch (D::Exception* excpt) | ||
| { | ||
| D::string s = excpt->toString(); | ||
| assert(memcmp(s.ptr + s.length - 9, "Hello C++", 9) == 0); | ||
| return true; | ||
| } | ||
| catch(...) | ||
| { | ||
| assert(false); | ||
| } | ||
| return false; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| // EXTRA_CPP_SOURCES: ldc_cpp_eh1.cpp | ||
|
|
||
| extern(C++) bool test_eh(); | ||
|
|
||
| extern(C++) | ||
| void throwException() | ||
| { | ||
| throw new Exception("Hello C++"); | ||
| } | ||
|
|
||
| void main() | ||
| { | ||
| bool rc = test_eh(); | ||
| assert(rc); | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Could you elaborate a bit on the ABI mismatch? I assumed ABI compliance between D and C++ would already be checked by dmd-testsuite...
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.
Isn't this just duplicating the normal – extern(D)! – class definition in C++ and hoping that it somehow works?
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.
If I understand rainers/druntime@9dce356 correctly, it allows you to catch a D exception in C++ by declaring a C++ type with the same class name as the native D exception in a
Dnamespace (convention © Rainer ;)). That's why each thrown exception's type incl. base types are 'mangled' twice. Note that MSVC EH is based on strings specifying an exception's types (incl. base types).The definition of the C++ type doesn't really matter, as long as the exception object isn't accessed; Rainer's test only uses
toString(), for which he wrote a specific C++ implementation anyway (calling back into druntime, apparently due to ABI mismatches). By duplicating the D class definitions ofObject,Throwableetc. I guess he wanted to pave the way for a catch-D-exceptions lib for C++.As soon as clang supports
extern "D"name mangling, we don't need this additional mangling for MSVC++ anymore. :DThere 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.
Yeah, that's what I gathered too – but what's way worse than the different mangling are the differences in object layout. I suppose you could manually "decode" and call the vtable entries on the C++ side, though, for a proper solution.
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 meant this test as a show case how easy it is now to mix exception handling between D and C++. Catching C++ exception in D needs a few changes to the front end (allowing C++ classes as catch type) that Walter added only very recently, so I guess it'll need some time until this is in LDC. Mirroring the D definitions with a C++ definition is just the same as declaring a C++ class in D.
Unfortunately, Walter chose a different ABI than the C++ compiler for x86 (http://dlang.org/spec/abi.html), especially
thisis passed in EAX, not ECX as for__thiscall. That's why mapping virtual functions doesn't work without making the class extern(C++) in D. I don't think this should be done to the D exceptions.The actual virtual functions are just for documentation here, just exposing the useful wrappers should be ok, too.
Writing the binding function
_d_toStringon the D side has the big advantage that D knows both sides of the ABI, so you don't have to dig into assembly. It could be generalized to call any virtual function by specifying the offset in the vtbl, though.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.
Yeah, stupid me, completely forgot about that for a moment. The fever I had the last few days must have damaged my brain...
Do you think this alternative C++ mangling +
_d_toStringshould be merged into druntime as-is? Or is it meant as prototype for a standardized upstream approach?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 not sure. This possibility is currently very specific to the WinEH implementation, I doubt it is feasible in dmd. I don't know if something similar would be possible for other platforms.