-
-
Notifications
You must be signed in to change notification settings - Fork 608
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
Translate _d_newThrowable hook to template
#13494
Conversation
|
Thanks for your pull request and interest in making D better, @teodutu! 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#13494" |
_d_newThrowable hook to template_d_newThrowable hook to template
|
dependant PR merged, please rebase this. |
59ef55a
to
9e470ab
Compare
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.
is this able to be tested in this PR?
|
@thewilsonator Yes. This lowering is enabled by
|
|
There are a few build kite failures, could you take a look. cc @atilaneves this fails on your projects |
Yes - but I don't know why it'd fall on me to go and see why. I downloaded the branch from the PR anyway and tried it on unit-threaded, and it seems this PR ends up changing the purity of The buildkite test projects are in CI exactly to try and catch this type of breakage. I'm more than happy to help and answer questions because of familiarity (or lack thereof) with the codebase. |
|
Rebase this and let's get it in. |
9e470ab
to
4d532f3
Compare
|
The buildkite test failed because the hook was impure. This was not verified in the tests, so I added a function to check qualifiers in |
src/dmd/dinterpret.d
Outdated
| auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, cast(StructDeclaration) cd, elems, e.type); | ||
| se.origin = se; | ||
| se.ownedByCtfe = OwnedBy.ctfe; | ||
| Expression eref = ctfeEmplaceExp!ClassReferenceExp(e.loc, se, e.type); |
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.
Do you mind explaining why is this necessary?
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.
eref needs to be a reference to this of the constructed class, in order to call interpretFunction below. This is why it needs to be a ClassReferenceExp. The ctor of ClassReferenceExp receives a StructLiteralExp [1]. Hence, the need for the "hack".
[1]
Lines 43 to 53 in bc3a0f1
| extern (C++) final class ClassReferenceExp : Expression | |
| { | |
| StructLiteralExp value; | |
| extern (D) this(const ref Loc loc, StructLiteralExp lit, Type type) | |
| { | |
| super(loc, EXP.classReference, __traits(classInstanceSize, ClassReferenceExp)); | |
| assert(lit && lit.sd && lit.sd.isClassDeclaration()); | |
| this.value = lit; | |
| this.type = type; | |
| } |
src/dmd/dinterpret.d
Outdated
| else if (fd.ident == Id._d_newThrowable) | ||
| { | ||
| // Treat `_d_newThrowable!E(args)` as `new E(args)` and interpret `E.ctor(args)`. | ||
| auto tc = e.type.toBasetype().isTypeClass(); | ||
| auto cd = tc.sym; | ||
|
|
||
| if (!cd.ctor) | ||
| { | ||
| e.error("`%s` cannot be constructed at compile time, because the constructor has no available source code", e.type.toChars()); | ||
| result = CTFEExp.cantexp; | ||
| return; | ||
| } | ||
|
|
||
| size_t totalFieldCount = 0; | ||
| for (ClassDeclaration c = cd; c; c = c.baseClass) | ||
| totalFieldCount += c.fields.dim; | ||
| auto elems = new Expressions(totalFieldCount); | ||
| size_t fieldsSoFar = totalFieldCount; | ||
| for (ClassDeclaration c = cd; c; c = c.baseClass) | ||
| { | ||
| fieldsSoFar -= c.fields.dim; | ||
| foreach (i, v; c.fields) | ||
| { | ||
| if (v.inuse) | ||
| { | ||
| e.error("circular reference to `%s`", v.toPrettyChars()); | ||
| result = CTFEExp.cantexp; | ||
| return; | ||
| } | ||
| Expression m; | ||
| if (v._init) | ||
| { | ||
| if (v._init.isVoidInitializer()) | ||
| m = voidInitLiteral(v.type, v).copy(); | ||
| else | ||
| m = v.getConstInitializer(true); | ||
| } | ||
| else | ||
| m = v.type.defaultInitLiteral(e.loc); | ||
| if (exceptionOrCant(m)) | ||
| return; | ||
| (*elems)[fieldsSoFar + i] = copyLiteral(m).copy(); | ||
| } | ||
| } | ||
|
|
||
| // Hack: store a ClassDeclaration instead of a StructDeclaration. | ||
| auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, cast(StructDeclaration) cd, elems, e.type); | ||
| se.origin = se; | ||
| se.ownedByCtfe = OwnedBy.ctfe; | ||
| Expression eref = ctfeEmplaceExp!ClassReferenceExp(e.loc, se, e.type); | ||
|
|
||
| UnionExp ue = void; | ||
| auto err = interpretFunction(&ue, cast(FuncDeclaration) cd.ctor, istate, e.arguments, eref); | ||
| if (exceptionOrCant(err)) | ||
| return; | ||
|
|
||
| eref.loc = e.loc; | ||
| result = eref; | ||
| return; | ||
| } |
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 block seems to be copied from the class branch of NewExp - refactor to that code into a function instead of duplicating it here.
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.
Wouldn't it be shorter and more expressive, albeit a bit less efficient, if I just created a NewExp and interpreted it directly?
| @@ -1096,8 +1096,11 @@ extern (C++) class ToElemVisitor : Visitor | |||
| } | |||
| else | |||
| { | |||
| assert(!(global.params.ehnogc && ne.thrownew), | |||
| "This should have been rewritten to `_d_newThrowable` in the semantic phase."); | |||
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 assert will trigger for COM / C++ classes which are not rewritten in expressionsem.d?
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're right. I changed this assert to the same condition as in expressionsem.d:
Lines 3727 to 3728 in bf6d206
| if (global.params.ehnogc && exp.thrownew && | |
| !cd.isCOMclass() && !cd.isCPPclass()) |
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 doesn't seem that the !isCOMclass() && !cd.isCPPclass() condition did not make it.
|
It seems that this is still failing a couple of projects on buildkite |
|
Looks like the undefined symbol errors are caused by the same underlying issue as using The compiler assumes druntime and Phobos are compiled with the same switch, and so most likely skips codegen for some templates encountered in druntime/Phobos imports. So once again a template culling problem when it comes to linking libraries compiled with different switches. Edit: And which wouldn't be an issue if |
|
@kinke : @teodutu compiled druntime locally with dip1008 enabled and then compiled unit-threaded with this version however the linker error persisted. One thing we could try is to compile both druntime and phobos with dip1008 and see if that works, however, phobos uses exceptions a lot and underlying dip1008 issues might surface (I remember looking at some dip1008 issue a few years ago and my thought back then was that it works for simple cases, but there are more complex uses where it's gonna fail; IIRC it was something regarding scope exceptions that could/should have escaped their scope). But if that doesn't work, what else can we do? |
|
I don't know all the DIP1008 details, but to me it seemed to be just a way to use exceptions with Besides fixing |
|
@kinke Using |
|
Please rebase. |
4d532f3
to
2770a0a
Compare
2770a0a
to
dc3273c
Compare
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.
Don't forget to delete the old hook in druntime!
Signed-off-by: Teodor Dutu <teodor.dutu@gmail.com>
Signed-off-by: Teodor Dutu <teodor.dutu@gmail.com>
Signed-off-by: Teodor Dutu <teodor.dutu@gmail.com>
This simplifies the lowering of `throw new E(args)` to `throw _d_newThrowable!E(args)`. During ctfe, the hook is interpreted like `new E(args)`. Signed-off-by: Teodor Dutu <teodor.dutu@gmail.com>
Signed-off-by: Teodor Dutu <teodor.dutu@gmail.com>
The new `_d_newThrowable` hook no longer calls `Error`'s ctor. Thus, the compiler must do this instead. Signed-off-by: Teodor Dutu <teodor.dutu@gmail.com>
dc3273c
to
4bac161
Compare
It was replaced by a template hook: - dlang#3661 - dlang/dmd#13494 Signed-off-by: Teodor Dutu <teodor.dutu@gmail.com>
|
How does this PR improve a |
|
@nordlow It's pretty transparent from the perspective of the developer. The PR makes the code in the compiler easier to maintain and contributes to dlang/project-ideas#25. The issue only mentions arrays, but there are other cases where |
It was replaced by a template hook: - dlang/druntime#3661 - dlang/dmd#13494 Signed-off-by: Teodor Dutu <teodor.dutu@gmail.com>
Pr dlang#14837 added templated lowering for _d_newclass and lowering field to NewExp. Pr dlang#13494 added templated lowering for _d_newThroable. This Pr merges those two. In expressionsem.d, instead of giving up the expression node and keeping just the id.expressionSemantic of it, the result is the whole node with all its previous fields and a new one, lowering, that is set to the previously returned value. In e2ir.d, for a newExpression, the expression is already created in the semantic phase with all the arguments needed, so the visitor will not recreate it, therefore the assert at line 1153 is no longer necessary. Signed-off-by: Andrei Rusanescu <andreirusanescu154@gmail.com>
Pr dlang#14837 added templated lowering for _d_newclass and lowering field to NewExp. Pr dlang#13494 added templated lowering for _d_newThroable. This Pr merges those two. In expressionsem.d, instead of giving up the expression node and keeping just the id.expressionSemantic of it, the result is the whole node with all its previous fields and a new one, lowering, that is set to the previously returned value. In e2ir.d, for a newExpression, the expression is already created in the semantic phase with all the arguments needed, so the visitor will not recreate it, therefore the assert at line 1153 is no longer necessary. Signed-off-by: Andrei Rusanescu <andreirusanescu154@gmail.com>
This PR lowers expressions such as
throw new E(args)to:when compiling with
-dip1008.The DRuntime PRs which implement the template
_d_newThrowableare:_d_newThrowabledruntime#3661_d_newThrowablereturn a fully constructedThrowabledruntime#3692