-
-
Notifications
You must be signed in to change notification settings - Fork 613
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
Fix issue 18472: betterC cannot use format at compile time. #14676
base: master
Are you sure you want to change the base?
Conversation
fb14d42
to
36f3353
Compare
compiler/src/dmd/backend/util2.d
Outdated
@@ -41,7 +41,7 @@ void file_progress() | |||
/**************************** | |||
* Clean up and exit program. | |||
*/ | |||
|
|||
@trusted |
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 required?
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 one is unrelated, the master
branch DMD was erroring because of a @system
call in @safe
code
@@ -715,7 +715,8 @@ void toObjFile(Dsymbol ds, bool multiobj) | |||
|
|||
override void visit(TypeInfoDeclaration tid) | |||
{ | |||
if (isSpeculativeType(tid.tinfo)) | |||
import dmd.globals : global; | |||
if (isSpeculativeType(tid.tinfo) || global.params.betterC) |
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 in love with this.
Should be 1 condition: does it need emission or not, rather than isSpeculative or if the compiler is in betterC.
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.e. do the logic somewhere.else
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 could also be if !global.params.useTypeInfo
. The problem is that the TypeInfo
is generated by CTFE, and DsymbolTable
gets populated with external references.
I think a better option would be to clean it up, I tried adding a global ctfe semaphore to keep track of how deep we are in startCTFE
(++
) and endCTFE
(--
), isInterpreting
(++
/--
) and actually forget about betterC by setting the useTypeInfo
to true
during CTFE. I was able to compile a string through std.format
that way but the ~30 phobos / druntime external references caused a linker problem and the application ended with the semaphore at 222. Without the semaphore, the compiler seems to consider it's not even in CTFE after a few calls deep within phobos. It looks like the Scope
is lost in a TemplateInstance
. It seems like a lot of work to get phobos running through ctfe in betterC
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.
Actually, a betterC CTFE symbol could almost be considered speculative? Hmm
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.
What I mean is that there's no single global state or symbol tracking for ctfe execution. It goes in and out of ctfe temporarily on occasion and in many cases the execution path code ends up in the binary.
@@ -0,0 +1,37 @@ | |||
/*******************************************/ |
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 could be a compiler test rather than a druntime one I think
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.
Where would that go? I couldn't find
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.
compiler/test/compilable or maybe runnable if absolutely 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.
I'm not sure the implementation is right. The ctfeGlobals.active
doesn't look like it respects scoping rules. It looks like the new logic is only active with -betterC
, so it gets very limited test coverage. I suspect it handles this wrong and allows you to cheat @nogc
:
auto getFun() {
if (__ctfe) {
static ubyte[] gcAlloc() @nogc {return new ubyte[10];}
return &gcAlloc;
}
return null;
}
immutable fun = getFun();
void main() {
fun();
}
@@ -206,6 +210,10 @@ void incArrayAllocs() | |||
++ctfeGlobals.numArrayAllocs; | |||
} | |||
|
|||
bool isInterpreting() { |
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 function looks pointless. It's also missing a DDoc comment and has the wrong brace style ({
should be on the next line).
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 function is currently the only way to know whether we're in CTFE
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 (ctfeGlobals.active)
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's marked private
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 added a new SCOPE.ctfeonly
which makes this fail with a @nogc
error correctly now
compiler/src/dmd/dinterpret.d
Outdated
@@ -227,6 +235,7 @@ struct CtfeGlobals | |||
int maxCallDepth = 0; // highest number of recursive calls | |||
int numArrayAllocs = 0; // Number of allocated arrays | |||
int numAssignments = 0; // total number of assignments executed | |||
bool active; // whether we are interpreting a ctfe 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.
How's this different from SCOPE.ctfe
?
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.
The SCOPE.ctfe
flag is not set when going through the interpret
phase which is why we get the TypeInfo
error within a static assert. Also, this flag seems to be temporarily turned off during execution anyways and is not reliable. https://github.com/dlang/dmd/blob/master/compiler/src/dmd/expressionsem.d#L3965
It does handle this wrong, because anything within
or without -betterC
|
Without |
Basically, this is the behavior I want to achieve
|
I think D needs to have a |
I think dmd could recognize that pattern and skip code gen for whatever is inside it.
That's somewhat similar to One simple solution is moving betterC errors from compile time to run time, by emitting |
I think the existing CFA code might be able to recognize the CTFE patterns. I tried doing it but I don't remember if it worked or not |
I'll add that. The other issue is that the code would not be |
Come to think about it, there should be a flag on each Dsymbol about whether it was identified in a chain of runtime calls to filter out ctfe references from being included in the final binary. Combined with |
Thanks for your pull request and interest in making D better, @etcimon! 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 references
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#14676" |
The Also, I think the compile-time errors for |
It could, but only if the code initially goes through CTFE and evaluates the condition that contains __ctfe. You can't reliably predict what would happen in that |
Needs spec PR since adding a new CTFE boolean pseudo-variable. See https://dlang.org/spec/function.html#interpretation . |
Are there instructions on how to do this? |
What guessing? |
The same code to recognize noreturn and so on should work for assert(CTFE) adding an entirely new identifier seems really extreme and also useless for some existing code. |
You mean Also, it would break any code that used |
@WalterBright you may want to take a look, as you were working on similar BetterC issues. |
I also made the changes in LDC Now I can use Diet Templates with a Webassembly project, which means they run in the client browser. The output HTML is correctly generated. I just need to setup an algorithm to selectively merge the HTML with the (spasm) structs and I can write most of a website using diet templates and D (without a GC) instead of React/Angular. https://github.com/etcimon/libwasm/tree/master/diet-ng
|
I rebased this in the most recent commit. However, it seems like everyone wants to sweep this under the rug. Is this going to require a rebase every month as it gets burried in pull hell? Should I just close it and abandon ctfe in betterC? |
@etcimon Let's give it a bit more time, please. I'll make sure it's on Walter's radar so he can look it over |
@etcimon can you please change the commit message to:
this is so the dlang bot can successfully associate it with the bug report. The "fix Issue NNNN" is the trigger. Is the test case in the PR the one you want to resolve? Is it a boiled down case from the bugzilla issue? yes, please rebase! |
I started work on a fix: |
Yes, it boils down to this. There are a lot of implementations of format but you need to be able to allocate an array on the GC. I made it work with diet templates in my fix as you can see with my comment, which builds an html string builder from D code at compile-time in betterC and displays it in the browser console entirely from webassembly |
However, I had a bug in my library that I couldn't replicate with a test yet, which is portrayed with |
@etcimon I think I have a handle on a good fix for this, and we'll see if we can get it merged with some alacrity. Thanks for your patience on this issue. |
Thanks @WalterBright, I didn't expect you to personally pick this up. There's other pieces that would be missing to make the standard format work, the general rule of thumb that I've learned to respect with CTFE in betterC is that your function has to compile with betterC before it can be used in CTFE, so for the standard library the other problem is that |
I'm sorry for neglecting the PR. I didn't consider it ready because of two outstanding issues:
Because of the second point, I brought the issue up in the Quarterly D Language Foundation Meeting last January. Mike hasn't posted a summary in the Announce Forum yet, but the summary of my part is:
Since then, Walter Bright made some incremental improvements: Currently I'm not sure what exactly needs to be done still to make In any case, I should have communicated this to you. |
Deprecating -betterC would definitely kill any potential of webassembly in D altogether. There's absolutely no way anyone would agree to embed the browser API in druntime, but what do I know? The current front runner for webassembly is Rust with this library: https://github.com/yewstack/yew I think D could do a better job, but if betterC is deprecated I might as well consider D a too high-level language altogether that tries to compete with python, and move on. |
There's no plan to do that without offering an alternative that covers the same grounds. Note that -betterC is not the only way to compile D without druntime dependencies: http://dpldocs.info/this-week-in-d/Blog.Posted_2020_07_27.html Ideally, druntime becomes more lightweight and pay as you go, meaning it doesn't drag in any features your code doesn't use. However, there's a long way to go. |
Those articles are interesting, it would definitely be nice to be able to have custom exceptions without pulling in druntime, it seems like you can write code that doesn't pull in druntime if you're careful. Obviously, a good addition to this would be a compiler flag that gives you errors you when you do, you know, just like betterC currently does. There's nothing wrong with adding features to betterC though, just like we're trying to do here. |
The issue with betterC isn't that people use it for weird targets but
rather that people use it to try and be efficient (i.e. where druntime
works fine) which then completely balkanizes the language in a way that
isn't introspectable inside the language and also causes lots of linker
errors if it sneaks into a dependency graph.
DRuntime can and is being made pay-as-you-go, eventually it will just emit
(if no hooks are used) what's needed for the runtime to initialize the
module correctly, And even that should be removed by the linker if unused.
…On Sat, 25 Feb 2023, 18:22 Etienne Cimon, ***@***.***> wrote:
Deprecating -betterC would definitely kill any potential of webassembly in
D altogether. There's absolutely no way anyone would agree to embed the
browser API in druntime, but what do I know? The current top runner for
webassembly is Rust with this library:
https://github.com/yewstack/yew
I think D could do a better job, but if betterC is deprecated I might as
well consider D a too high-level language altogether that tries to compete
with python, and move on.
—
Reply to this email directly, view it on GitHub
<#14676 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABLI75G5222B6BKWMBVWUT3WZJEWNANCNFSM6AAAAAASXHDS6Q>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
If people are using betterC to build their library, I don't believe that should even be worth mention when developing the language because by definition they declared independence on it and are totally fine with being ignored. The articles above discusses the alternative to betterC which is declaring a custom object module, that should be much worse because it overrides druntime in a way that you can't even add the library as a dependency. |
It seems like the main concerns about betterC could be addressed by putting them in a separate cluster in the dub registry. On my end, I don't think I could develop this web framework without having a compiler that helps users avoid druntime. |
For various reasons,
isInputRange!string
is nowfalse
even during CTFE because astring
in betterC doesn't have the requirements to be considered a range. TheAppender
andformat
will not work, much like a lot of the standard library.However, CTFE is mainly based on being able to allocate a
new T
during theinterpret
phase, which means we need to includeTypeInfo
in the code but avoid the external references during linking. These changes open up the opportunity to do it in aif (__ctfe)
statement, so that the same function can be used during runtime inbetterC
without aTypeInfo
orGC allocation
error.I'm currently working on adding
diet-ng
to the @skoppe/spasm library using my own memory allocation libraries that will fall back tonew T
ornew T[]
when necessary, and currently CTFE is nearly impossible due to the allocations being blocked.