-
-
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
fix Issue 21574 Evaluate Pure Functions With CTFE #10452
Conversation
Thanks for your pull request, @WalterBright! 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#10452" |
36b8a72
to
cc6ff29
Compare
@UplinkCoder: I wonder how this will affect compilation time if used together with newCTFE, which I presume has a larger latency than the current CTFE-evalutor... |
I don't think that this quite what we want. There are two problems: (1) We definitely do not want all CTFEable functions to use CTFE. Because of this, you'd need to remove the 'pure' attribute from many such functions. (2) Not all pure functions can actually be run at CTFE. For example a pure function may call an extern(C) function. Essentially, this PR repurposes |
Additionally this doesn't support the case of forcing CTFE even when a parameter is not a literal. Eg.I'd like to be able to force |
Are we in need of a more direct syntax for calling functions at compile time? Opposite to
and template parameterized overloads. |
How much more complex is something like I think Don's point about the meaning of Sure, we could make evaluation of pure functions the default, and add a special wrapper |
My proposal to Walter was this (in the context of HexString): Templates are the wrong tool for this job. They create an instance of the template for every string you use, And the mangled name is stored in the binary, along the contents of the template. Converting a UTF8 string to a string of ubytes is a perfect task for CTFE. And in the case where you're creating a named sequence of bytes, this works perfectly, right now: // a global static, not an enum, so that it is stored in only place in the binary The problem with this solution, though, is that it only works when the function call gets CTFE'd. So it doesn't work (for example) when used to initialize a stack variable. So, hexString is implemented as a template for only one reason: to force it to be evaluated at compile time. In my view a much nicer solution would be to add a function attribute, to force a function to be CTFEd. One possibility would be @ctfe. Another interesting one would be to repurpose the magic __ctfe keyword. This would have two effects: (1) Any call to such a function would be CTFEd during the const folding pass. (2) The function should not be written to the .obj file. It does not exist at runtime. (Note that __ctfe is not transitive. A __ctfe function can call any runtime function, just like normal CTFE). I don't know where you would put the __ctfe, there are a few possibilities, including: string __ctfe foo(string s); string foo(string s) __ctfe; __ctfe string foo(string s); I suspect that a great many extant templates are like this. They're just using template to force the use of CTFE. I think that a very large fraction of templates which accept value parameters, fall into this category. |
I am agreeing with those who commented before me. Invoking CTFE (on the top-level) has to predictable by a simple rule. @nordlow As for your question, newCTFE does currently have somewhat higher latency in trivial cases, yes. That's an implementation issue and not necessarily systemic. |
It's easy enough to cause these to be run at runtime:
This is because the front end does not attempt data flow analysis optimizations. Another way is to insert into the pure function a call to another pure function, where the source isn't available to the compiler.
Exactly. In such cases where CTFE fails, the function is run at runtime. |
If |
It causes a template to be evaluated and the arguments wind up in the mangled template name, which if the arguments are large can be a serious problem. A better approach is to use the |
Don, you've (rightfully) complained to me about the current attribute soup for functions. You're proposing adding more!
Removing unreferenced functions is a more general problem, and is dealt with by the linker.
Then the |
How do other languages handle this? C++ has |
How about a solution that also addresses the code bloat problem? See dlang/DIPs#177 (comment) |
3e3f7e5
to
44d2265
Compare
44d2265
to
5940e34
Compare
Shelving for later. Leave bug report open. |
This implements dlang/DIPs#177
dlang/phobos#7211 takes advantage of this.
For a call to a
pure
function, if the function arguments are Literals or are Expressionsthat are representable by Literals after the normal semantic processing of them, and the
return type of the function can be represented by a Literal, then the function is
evaluated at compile time using CTFE.
If the call cannot be evaluated using CTFE, such as if the
pure
function contains impuredebug
statements in the path of CTFE execution, no error is generated, the function is simplyevaluated at run time instead.
Without this change, common code patterns use templates and enums to force compile time execution, making the code more complex than necessary.