digitalmars.D - Request for Comment assert(__ctfe)
- Stefan Koch (26/26) Apr 05 2020 Hi Guys,
- Stefan Koch (5/8) Apr 05 2020 One more thing.
- Walter Bright (2/3) Apr 06 2020 I'll try not to shoot myself in the foot.
- Petar Kirov [ZombineDev] (4/7) Apr 05 2020 I had a similar thought some time ago:
- Adam D. Ruppe (2/3) Apr 05 2020 good enough for me.
- Basile B. (6/11) Apr 05 2020 I'd prefer a new func attribute `@ctfe`.
- Stefan Koch (4/19) Apr 05 2020 Don't we have enough attributes already?
- Basile B. (5/24) Apr 05 2020 I don't know. The criticism I have aginst func attributes is more
- Jonathan Marler (13/28) Apr 05 2020 I agree that a function attribute makes more sense for a feature
- Johannes Pfau (8/13) Apr 07 2020 The compiler can really not know if a function is supposed to be callabl...
- tsbockman (7/12) Apr 05 2020 Ideally it should only skip codegen if there are no statements
- Stefan Koch (4/18) Apr 05 2020 So it's much easier to just scan for assert(__ctfe);
- Steven Schveighoffer (6/7) Apr 05 2020 It seems like a good idea, except what you will see is a linker error if...
- Stefan Koch (4/12) Apr 05 2020 Yes. that is possible.
- Steven Schveighoffer (8/22) Apr 05 2020 What do you mean it never happens?
- Petar Kirov [ZombineDev] (45/48) Apr 05 2020 Another, more radical and interesting option is to not perform
- Stefan Koch (10/17) Apr 05 2020 Seems like you are reading my mind.
- Petar Kirov [ZombineDev] (6/27) Apr 05 2020 Great! Perhaps we should write a DIP to specify the semantics of
- Johannes Pfau (14/42) Apr 07 2020 How would such a lazy compilation model work without explicit 'export'
- Petar Kirov [ZombineDev] (138/161) Apr 08 2020 In my post [1] I said that the `export` storage class is the key
- Johannes Pfau (7/11) Apr 08 2020 Thanks for taking the time to write such a detailed answer. I think I'll...
- Petar Kirov [ZombineDev] (4/15) Apr 08 2020 Thanks! I do realize that D compilation is a way more complicated
- Timon Gehr (10/30) Apr 05 2020 Make sure it works with `in` contracts:
- Stefan Koch (3/15) Apr 05 2020 Oh good idea.
- Timon Gehr (2/20) Apr 05 2020 Great, thanks! :)
- Meta (7/38) Apr 05 2020 We likely get the shorthand version for free as well:
- Stefan Koch (2/24) Apr 05 2020 No. the in contract was already a pain in the butt.
- Adam D. Ruppe (3/11) Apr 05 2020 That IS an in contract. idk about the implementation but from the
- Timon Gehr (5/30) Apr 05 2020 I don't understand how you would implement it in a way where the above
- Stefan Koch (5/9) Apr 05 2020 I see. Well in that case it'll work out of the box.
- Timon Gehr (17/29) Apr 05 2020 For no reason at all. It's the appropriate place to expand simple
- Stefan Koch (3/8) Apr 06 2020 I don't mind the what. I just mind the when. But it's not a big
- Johan (12/22) Apr 06 2020 Offtopic.
- Atila Neves (3/10) Apr 06 2020 Wouldn't it be easier to skip codegen for private functions that
- Stefan Koch (8/20) Apr 06 2020 Easier from the user-perspective yes.
- Atila Neves (4/18) Apr 06 2020 Where N and M are all calls and private functions in one module,
- Stefan Koch (2/21) Apr 06 2020 in (__ctfe) is already supported.
- Dominikus Dittes Scherkl (3/7) Apr 06 2020 It was already explained, this will expand to the same code, so
- Stefan Koch (5/13) Apr 06 2020 Well technically I had to do a bit of work for InContracts
- Johannes Pfau (28/45) Apr 07 2020 In fact, you can't do that in current D. I thought about it some time
- Jacob Carlborg (5/60) Apr 07 2020 You can also bypass "private" using __traits(getMemeber) or using an
- Walter Bright (2/4) Apr 06 2020 There's no reason the CTFE-only function can't be global.
- Atila Neves (4/8) Apr 07 2020 No, there isn't. But in my experience nearly all functions I
- Adam D. Ruppe (3/8) Apr 07 2020 I've done it both ways. If it can be accomplished easily enough
- Walter Bright (4/4) Apr 06 2020 Sounds ok to me, as long as the assert(__ctfe) is the first statement in...
- Stefan Koch (3/7) Apr 07 2020 In order to support contracts we need to go through all the
- Walter Bright (4/13) Apr 07 2020 You could move it up earlier in the semantic analysis. When semantic ana...
- Atila Neves (4/8) Apr 07 2020 I think the problem with relying on the linker is that the user
- Walter Bright (2/4) Apr 07 2020 True
- Steven Schveighoffer (6/15) Apr 07 2020 Isn't there an issue for better C as well? If a function can't be
- Atila Neves (3/19) Apr 08 2020 Good question, me neither.
- Johannes Pfau (4/14) Apr 08 2020 The answer is simple. It simply does not work today ;-)
- Johannes Pfau (56/61) Apr 07 2020 Very nice work, Stefan!
- Stefan Koch (32/45) Apr 07 2020 I can confirm with the patch there are no template-instances in
- Guillaume Piolat (2/4) Apr 07 2020 Very cool! Thanks.
- Johannes Pfau (19/39) Apr 07 2020 The example above actually already compiles with -betterC, as the check
- Steven Schveighoffer (8/26) Apr 07 2020 Ironically, ctfe can't deal with TypeInfo today.
- Johannes Pfau (30/60) Apr 08 2020 I'm not sure what exactly you're referring to, but this code compiles
- Stefan Koch (10/53) Apr 08 2020 The detection of assert __ctfe in the function body _can_ be done
- Dennis (5/7) Apr 08 2020 assert(__ctfe) does not express that you STATICALLY know it only
- Stefan Koch (5/12) Apr 08 2020 The only reason why I used assert (__ctfe) not static assert
- Dennis (31/35) Apr 08 2020 Indeed, and that should make you think how you can properly
- Stefan Koch (9/11) Apr 08 2020 I have tried doing that for a long time and gave up.
- Dennis (8/12) Apr 09 2020 Let me be clear in case you're implying my critique is for the
- Timon Gehr (4/7) Apr 09 2020 It's obvious how to make that work, but is it really worth the effort
- Dennis (8/15) Apr 09 2020 That could be a good POC implementation to start with, from there
- Jonathan Marler (8/21) Apr 08 2020 This may be a naive suggestion, but how hard would it be to make
- Johannes Pfau (19/43) Apr 08 2020 I'd guess very hard. To be consistent with the rest of the language, you...
- Jonathan M Davis (16/23) Apr 08 2020 Sure, but since you're asserting that it should never run except during
- Dennis (31/40) Apr 09 2020 It's not an optimization, it is a breaking change that can turn
- H. S. Teoh (9/14) Apr 08 2020 [...]
- Johannes Pfau (11/34) Apr 08 2020 The important point is that we do not bake in semantics now which might
- Steven Schveighoffer (17/74) Apr 08 2020 I misread your example! I thought you were doing typeid(T).toString. I
- Johannes Pfau (28/39) Apr 08 2020 I've posted a proof-of-concept PR using pragma(ctfe) here:
- Jacob Carlborg (18/49) Apr 07 2020 For many years I wanted a feature that could indicate a function is only...
- tsbockman (4/17) Apr 07 2020 Catching an AssertError thrown by an assert statement is
- Jacob Carlborg (23/26) Apr 08 2020 Ok, let me tweak the example a bit:
- Stefan Koch (5/16) Apr 07 2020 firstly Does anybody actually do this?
- Jacob Carlborg (17/33) Apr 08 2020 Ok, let me tweak the example a bit:
- Steven Schveighoffer (13/52) Apr 08 2020 I think it's a breaking change, just like flagging any obvious error
- Steven Schveighoffer (15/18) Apr 08 2020 another interesting case:
- Steven Schveighoffer (3/4) Apr 08 2020 Ugh, that should have been foo();, forgot to edit that.
- Basile B. (8/13) Apr 09 2020 Other and new thought.
- Stefan Koch (6/23) Apr 09 2020 well ... splitting the function in two versions comes with the
Hi Guys, I am currently working on speeding up dmd. In the presence of templates and ctfe. and one thing that stood out is that we do codegen for symbols which are never used. (and hopefully eliminated by a smart linker but eh ...) I've seen the following pattern in the wild. string GenerateMixin(string[] params) { assert(__ctfe); .... more code .... } that means if we see assert(__ctfe) inside the outermost scope of a function body ( not in a branch) then we know that this function would assert if called at runtime. And therefore no correct code can be calling it. which also means we can forgo having code-gen or optimization for the function body. and reduce the count of names which has to get mangled. They only downside to this, is that giving assert(__ctfe) the special meaning to skip codegen might be confusing to some people .... then again you wouldn't use assert(__ctfe) unless you expect that function to not be available at run-time What do you guys think? Cheers, Stefan
Apr 05 2020
On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:Hi Guys, .... What do you guys think?One more thing. The implementation of this is not that hard, and almost done already. (just in case you're getting trigger happy Walter. )
Apr 05 2020
On 4/5/2020 5:13 AM, Stefan Koch wrote:(just in case you're getting trigger happy Walter. )I'll try not to shoot myself in the foot.
Apr 06 2020
On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:Hi Guys, .... What do you guys think?I had a similar thought some time ago: https://github.com/dlang/DIPs/pull/177#issuecomment-539894029 ;)
Apr 05 2020
On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:What do you guys think?good enough for me.
Apr 05 2020
On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:Hi Guys, [...] What do you guys think? Cheers, StefanI'd prefer a new func attribute ` ctfe`. Also I find the current implementation unplesant. Cant you just check the assertion when they are already visited elsewhere e.g in dmd.expressionsem.ExpressionSemanticVisitor.visit(AssertExp) ? Also what if we are in a contract ?
Apr 05 2020
On Sunday, 5 April 2020 at 13:26:22 UTC, Basile B. wrote:On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:Don't we have enough attributes already? I _could_ but then it's hard to know if I am in the top-level of the function body.Hi Guys, [...] What do you guys think? Cheers, StefanI'd prefer a new func attribute ` ctfe`. Also I find the current implementation unplesant. Cant you just check the assertion when they are already visited elsewhere e.g in dmd.expressionsem.ExpressionSemanticVisitor.visit(AssertExp) ? Also what if we are in a contract ?
Apr 05 2020
On Sunday, 5 April 2020 at 14:04:12 UTC, Stefan Koch wrote:On Sunday, 5 April 2020 at 13:26:22 UTC, Basile B. wrote:I don't know. The criticism I have aginst func attributes is more that their style are mixed (i.e w/ or w/o ' '). Anyway I'm not strongly against your way, it's just that in a perfect world I imagine ctfe rather.On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:Don't we have enough attributes already?Hi Guys, [...] What do you guys think? Cheers, StefanI'd prefer a new func attribute ` ctfe`. Also I find the current implementation unplesant. Cant you just check the assertion when they are already visited elsewhere e.g in dmd.expressionsem.ExpressionSemanticVisitor.visit(AssertExp) ? Also what if we are in a contract ?
Apr 05 2020
On Sunday, 5 April 2020 at 13:26:22 UTC, Basile B. wrote:On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:I agree that a function attribute makes more sense for a feature like this, however, this solution doesn't solve the general case (i.e. elide functions that are only called at compile-time but don't have assert(__ctfe) because they are available to be called at runtime). Given that, I believe solving the general case is only a matter of implementation rather than a language change. So I would hate to add a new language feature that would become obselete once the tooling is better. So I say yes, I'd be fine with this "hack" to temporarily provide a path for programs to create CTFE-ONLY functions that won't go to code generation. It's better than the status-quo and can be removed if we ever solve the general case.Hi Guys, [...] What do you guys think? Cheers, StefanI'd prefer a new func attribute ` ctfe`. Also I find the current implementation unplesant. Cant you just check the assertion when they are already visited elsewhere e.g in dmd.expressionsem.ExpressionSemanticVisitor.visit(AssertExp) ? Also what if we are in a contract ?
Apr 05 2020
Am Sun, 05 Apr 2020 16:00:42 +0000 schrieb Jonathan Marler:So I say yes, I'd be fine with this "hack" to temporarily provide a path for programs to create CTFE-ONLY functions that won't go to code generation. It's better than the status-quo and can be removed if we ever solve the general case.The compiler can really not know if a function is supposed to be callable at runtime, see https://forum.dlang.org/post/ r6hotc$28au$2 digitalmars.com for details. It could probably work if we decide to introduce 'export', but there was no consensus on that for years. -- Johannes
Apr 07 2020
On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:They only downside to this, is that giving assert(__ctfe) the special meaning to skip codegen might be confusing to some people .... then again you wouldn't use assert(__ctfe) unless you expect that function to not be available at run-time What do you guys think?Ideally it should only skip codegen if there are no statements with side-effects before the assert(__ctfe). However, I think it's fine to do it your way if that's easier to implement in the compiler, as long as normal code gen and optimization is still enabled for functions containing this construct, as a workaround: if(!__ctfe) assert(0);
Apr 05 2020
On Sunday, 5 April 2020 at 13:54:19 UTC, tsbockman wrote:On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:So it's much easier to just scan for assert(__ctfe); I've just implemented it and the projects on the dlang buildkite are green.They only downside to this, is that giving assert(__ctfe) the special meaning to skip codegen might be confusing to some people .... then again you wouldn't use assert(__ctfe) unless you expect that function to not be available at run-time What do you guys think?Ideally it should only skip codegen if there are no statements with side-effects before the assert(__ctfe). However, I think it's fine to do it your way if that's easier to implement in the compiler, as long as normal code gen and optimization is still enabled for functions containing this construct, as a workaround: if(!__ctfe) assert(0);
Apr 05 2020
On 4/5/20 8:11 AM, Stefan Koch wrote:What do you guys think?It seems like a good idea, except what you will see is a linker error if you call it. Which is not very friendly or gives the right impression. Is there a way we can have the compiler give an error when it sees this during compile-time? -Steve
Apr 05 2020
On Sunday, 5 April 2020 at 14:25:27 UTC, Steven Schveighoffer wrote:On 4/5/20 8:11 AM, Stefan Koch wrote:Yes. that is possible. However actually it never happens :)What do you guys think?It seems like a good idea, except what you will see is a linker error if you call it. Which is not very friendly or gives the right impression. Is there a way we can have the compiler give an error when it sees this during compile-time? -Steve
Apr 05 2020
On 4/5/20 10:26 AM, Stefan Koch wrote:On Sunday, 5 April 2020 at 14:25:27 UTC, Steven Schveighoffer wrote:I'd be fully on board then.On 4/5/20 8:11 AM, Stefan Koch wrote:Yes. that is possible.What do you guys think?It seems like a good idea, except what you will see is a linker error if you call it. Which is not very friendly or gives the right impression. Is there a way we can have the compiler give an error when it sees this during compile-time?However actually it never happens :)What do you mean it never happens? I get that code that builds and runs correctly today will build with this change. But development is full of writing code that doesn't work, running the compiler, and fixing the errors shown. When the error is a link error, this will be completely confusing. -Steve
Apr 05 2020
On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:Hi Guys, ... What do you guys think?Another, more radical and interesting option is to not perform codegen unless it's actually necessary. Instead of blacklisting ` ctfe` or `assert(__ctfe)` functions, have a whitelist of what functions are allowed to codegen-ed. Specifically, do not perform codegen for any function unless that function: A) is marked, or inferred as `export` or called from such function (transitively) B) is part of an aggregate (module, union, class, struct, interface, template) marked as `export`, or called from a function part of such (By module marked as `export` I mean `export module foo;`, as opposed to `module foo; export:`) C) is `main`, or it's called from `main` (in these cases it's inferred as `export`) D) is a `unittest`, or called from one (under `version(unittest)` `unittest`s (and functions they call) are inferred as `export`) E) is marked as `extern($lang)` or called from such function (again inferred as `export` in such cases) F) is virtual, or called from such function (again inferred as `export` in those cases) `export` must be a function storage class orthogonal to protection modifiers, just like `extern`. Yeah, it will break the world, so this new compilation strategy should be opt-in via a switch (e.g. `-ix`, `-lazy`, `--as-needed`, etc.). I suspect it will play nicely with the existing `-i` ;) Implications? From top of my head: 1. No need for a new ` cttfe` function attribute, or to treat `assert(__ctfe)` in special way. Though, on second thoughts, perhaps it should be an error to have non-conditional `assert(__ctfe)` inside `export`-ed functions. 2. Regular functions gain some of the special powers of template ones - specifically, they're codegen-ed only if needed. Before, to make druntime/phobos functions accessible from DasBetterC we had to make them templates. Now this awkward technique (what's the point of having a template with no parameters? Non-template auto-returning functions also have attribute inference) is no longer needed. 3. Compilation speed and code bloat are reduced 4. D libraries become kind of like header-only C++ libraries. 5. Until now object files (or static libraries) were a primary build caching technique. Now a per-function caching technique would be much more helpful.
Apr 05 2020
On Sunday, 5 April 2020 at 18:25:10 UTC, Petar Kirov [ZombineDev] wrote:On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:Seems like you are reading my mind. Indeed this is one of next steps ... assert(__ctfe) did not break a single package, in out CI! Therefore I do now have enough confidence in crawling the dynamic dependencies outwards from the entry point and exported functions. That however is for the future and will require me to do some theoretical work, in order to proof to myself that it actually is feasible and won't end up in a nightmare of subtly broken builds.[...]Another, more radical and interesting option is to not perform codegen unless it's actually necessary. Instead of blacklisting ` ctfe` or `assert(__ctfe)` functions, have a whitelist of what functions are allowed to codegen-ed. [...]
Apr 05 2020
On Sunday, 5 April 2020 at 18:30:25 UTC, Stefan Koch wrote:On Sunday, 5 April 2020 at 18:25:10 UTC, Petar Kirov [ZombineDev] wrote:Great! Perhaps we should write a DIP to specify the semantics of such a lazy compilation model? An even more extreme option would be to not perform semantic analysis on non-`export`-ed functions. This should bring some really high gains, though it would be the trickiest to adopt option for users.On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:Seems like you are reading my mind. Indeed this is one of next steps ... assert(__ctfe) did not break a single package, in out CI! Therefore I do now have enough confidence in crawling the dynamic dependencies outwards from the entry point and exported functions. That however is for the future and will require me to do some theoretical work, in order to proof to myself that it actually is feasible and won't end up in a nightmare of subtly broken builds.[...]Another, more radical and interesting option is to not perform codegen unless it's actually necessary. Instead of blacklisting ` ctfe` or `assert(__ctfe)` functions, have a whitelist of what functions are allowed to codegen-ed. [...]
Apr 05 2020
Am Sun, 05 Apr 2020 18:40:31 +0000 schrieb Petar Kirov [ZombineDev]:On Sunday, 5 April 2020 at 18:30:25 UTC, Stefan Koch wrote:How would such a lazy compilation model work without explicit 'export' anotations? If I wanted to build a proprietary library libfoo.so and provide only .di files with stripped function bodies, all functions have to be compiled into the .so file. But how does the compiler know the result is going to be a shared library in a separate compilation model, where the compiler produces only an object file? I guess such a lazy compilation model might be quite interesting, but as it is a quite radical idea, it needs lots of thinking, proper specification and testing first. (Testing as you'll probably have to emit everything as weak symbols then, and you probably want to test how linkers deal with that if you make excessive use of it) -- JohannesOn Sunday, 5 April 2020 at 18:25:10 UTC, Petar Kirov [ZombineDev] wrote:Great! Perhaps we should write a DIP to specify the semantics of such a lazy compilation model? An even more extreme option would be to not perform semantic analysis on non-`export`-ed functions. This should bring some really high gains, though it would be the trickiest to adopt option for users.On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:Seems like you are reading my mind. Indeed this is one of next steps ... assert(__ctfe) did not break a single package, in out CI! Therefore I do now have enough confidence in crawling the dynamic dependencies outwards from the entry point and exported functions. That however is for the future and will require me to do some theoretical work, in order to proof to myself that it actually is feasible and won't end up in a nightmare of subtly broken builds.[...]Another, more radical and interesting option is to not perform codegen unless it's actually necessary. Instead of blacklisting ` ctfe` or `assert(__ctfe)` functions, have a whitelist of what functions are allowed to codegen-ed. [...]
Apr 07 2020
On Tuesday, 7 April 2020 at 17:33:03 UTC, Johannes Pfau wrote:In my post [1] I said that the `export` storage class is the key to making this work. The way I envision this is similar to a copying garbage collector: 1. [MARK] Starting from the set of ~GC~ CG roots [2] the compiler traverses the static call graph [3] and marks any callees as `export` (i.e. the `export` inference step in my proposal). All functions determined to have the `export` attribute are added to the code generation queue 2. [COPY] Do code generation by poping function from the queue until it becomes empty. 3. (Optional) produce a report of all functions that were not added to the queue. [1]: https://forum.dlang.org/post/xbllqrpvflazfpowizwj forum.dlang.org [2]: CG (call graph) roots: all functions marked explicitly as `export`, or implicitly under rules B) - F) in my post [1] (e.g. `main()`, `unittest`s, virtual functions, etc.) [3]: After statements inserted from `static`, `version` and `mixin` declarations are resolved, the set of all functions that may be called from a given function. Even if a function is called conditionally at runtime, it's still part of the static call graph.How would such a lazy compilation model work without explicit 'export' animations?On Sunday, 5 April 2020 at 18:25:10 UTC, Petar Kirov [ZombineDev] wrote:Another, more radical and interesting option is to not perform codegen unless it's actually necessary. Instead of blacklisting ` ctfe` or `assert(__ctfe)` functions, have a whitelist of what functions are allowed to codegen-ed. [...]If I wanted to build a proprietary library libfoo.so and provide only .di files with stripped function bodies, all functions have to be compiled into the .so file. But how does the compiler know the result is going to be a shared library in a separate compilation model, where the compiler produces only an object file?To produce the libfoo.{so,dll,dylib}, I assume that you have a whole package of D modules that you want to compile. --- (The case where libfoo is produced from a single D module is the trivial base case: only functions determined to be `export` will be part of the object file, from which libfoo will be produced.) Also, as in C++ (AFAIU), templates can't be part of your dynamic library ABI, only specific template instances can be. If type templates participate in the function signature (the parameter types, or return type) of an `export`-ed function, then those type templates are inferred to be `export` as well (and all of their members). I suspect we can do better here, but it's easier to start pessimistically to relax the rules later when we have a better formal model an empirical experience. --- So, finally, how would we produce a dynamic library? 1. In our implementation files (*.d) we would mark as `export` all public functions that we want to be part of our dynamic library API/ABI. 2. When the compiler produces *.di header files it would include the declarations of only public, protected or package symbols that are determined to be export. 3. When the object files are produced all `export` functions will be compiled (including private ones, i.e. private symbols, called from public exported ones). 4. The rest of the symbols that are not determined to be `export` are discarded. --- All in all, what we're left with is: 1. A strict compilation mode in which only symbols determined to be `export` are included in libraries. This way we have a much more precise definition of ABI. 2. A lazy compilation mode, based on (dmd -i) in which the compiler automatically imports and compiles functions as needed, starting from `main()`. In a package-wise compilation (not separate compilation), regular free functions are treated like template functions - they're not compiled unless used. Actually 1. and 2. are exactly the same compilation strategy, just very different use cases ;)I guess such a lazy compilation model might be quite interesting, but as it is a quite radical idea, it needs lots of thinking, proper specification and testing first. (Testing as you'll probably have to emit everything as weak symbols then, and you probably want to test how linkers deal with that if you make excessive use of it)I don't think we should rely that much on linkers for object file-level GC. The compiler shouldn't produce functions that are not determined to be `export` in the first place. Some examples: -------------------- module app; string generateMixin(T)(string b) { assert(__ctfe); return T.stringof ~ " " ~ b ~ ";"; } void main() nogc { mixin(generateMixin!string("b")); } -------------------- `dmd -c app.d` should produce an object file with a single (empty) function - `main()`; --------------------------- module foo; private void privateFunc() {} public void publicTemplate(T)() { privateFunc(); } --------------------------- Q: How would this work? A: Uner my proposal, the compiler should produce an **empty** object file. What could work is the following: --------------------------- module foo; private void privateFunc() {} public void publicTemplate(T)() { privateFunc(); } // the obvious way: export void publicFunc() { publicTemplate!int(); } // the syntax sugar way 1a: export alias publicFunc = publicTemplate!int; // the syntax sugar way 1b: export { alias publicFunc = publicTemplate!int; alias publicFunc = publicTemplate!string; } // the syntax sugar way 2: export { publicTemplate!int; publicTemplate!string; } // Note: the syntax sugar is not part of my proposal, // as it's not important for now. --------------------------- Or: --------------------------- module foo; private void privateFunc() {} public void publicTemplate(T)() { privateFunc(); } ---- module bar; import foo; export void actuallyPublicInterfaceFunction() { publicTemplate!int(); } --- dmd -i bar.d --------------------------- In this way we tell the compiler to compile the exported function in `bar` as well as any other functions that they may call.
Apr 08 2020
Am Wed, 08 Apr 2020 15:07:32 +0000 schrieb Petar Kirov [ZombineDev]:--------------------------- In this way we tell the compiler to compile the exported function in `bar` as well as any other functions that they may call.Thanks for taking the time to write such a detailed answer. I think I'll have to spend some more time thinking about this to convince myself that it really covers all cases. Anyway, a very interesting idea. -- Johannes
Apr 08 2020
On Wednesday, 8 April 2020 at 20:07:49 UTC, Johannes Pfau wrote:Am Wed, 08 Apr 2020 15:07:32 +0000 schrieb Petar Kirov [ZombineDev]:Thanks! I do realize that D compilation is a way more complicated process than my simplified model. My idea needs to be better formalized and to endure more scrutiny ;)--------------------------- In this way we tell the compiler to compile the exported function in `bar` as well as any other functions that they may call.Thanks for taking the time to write such a detailed answer. I think I'll have to spend some more time thinking about this to convince myself that it really covers all cases. Anyway, a very interesting idea.
Apr 08 2020
On 05.04.20 14:11, Stefan Koch wrote:Hi Guys, I am currently working on speeding up dmd. In the presence of templates and ctfe. and one thing that stood out is that we do codegen for symbols which are never used. (and hopefully eliminated by a smart linker but eh ...) I've seen the following pattern in the wild. string GenerateMixin(string[] params) { assert(__ctfe); .... more code .... } that means if we see assert(__ctfe) inside the outermost scope of a function body ( not in a branch) then we know that this function would assert if called at runtime.Make sure it works with `in` contracts: string generateMixin(string[] params)in{ assert(__ctfe); }do{ .... more code .... } (The plain assertion slightly hurts my eyes, because if it fails, that failure would be attributable to the GenerateMixin function, whereas with the `in` contract it is clear that the caller is at fault.)
Apr 05 2020
On Sunday, 5 April 2020 at 20:31:15 UTC, Timon Gehr wrote:On 05.04.20 14:11, Stefan Koch wrote:Oh good idea. I don't use contracts myself but that's easy to add.[...]Make sure it works with `in` contracts: string generateMixin(string[] params)in{ assert(__ctfe); }do{ .... more code .... } (The plain assertion slightly hurts my eyes, because if it fails, that failure would be attributable to the GenerateMixin function, whereas with the `in` contract it is clear that the caller is at fault.)
Apr 05 2020
On 05.04.20 22:39, Stefan Koch wrote:On Sunday, 5 April 2020 at 20:31:15 UTC, Timon Gehr wrote:Great, thanks! :)On 05.04.20 14:11, Stefan Koch wrote:Oh good idea. I don't use contracts myself but that's easy to add.[...]Make sure it works with `in` contracts: string generateMixin(string[] params)in{ assert(__ctfe); }do{ .... more code .... } (The plain assertion slightly hurts my eyes, because if it fails, that failure would be attributable to the GenerateMixin function, whereas with the `in` contract it is clear that the caller is at fault.)
Apr 05 2020
On Sunday, 5 April 2020 at 20:31:15 UTC, Timon Gehr wrote:On 05.04.20 14:11, Stefan Koch wrote:We likely get the shorthand version for free as well: string generateMixin(...) in(__ctfe) { ... }Hi Guys, I am currently working on speeding up dmd. In the presence of templates and ctfe. and one thing that stood out is that we do codegen for symbols which are never used. (and hopefully eliminated by a smart linker but eh ...) I've seen the following pattern in the wild. string GenerateMixin(string[] params) { assert(__ctfe); .... more code .... } that means if we see assert(__ctfe) inside the outermost scope of a function body ( not in a branch) then we know that this function would assert if called at runtime.Make sure it works with `in` contracts: string generateMixin(string[] params)in{ assert(__ctfe); }do{ .... more code .... } (The plain assertion slightly hurts my eyes, because if it fails, that failure would be attributable to the GenerateMixin function, whereas with the `in` contract it is clear that the caller is at fault.)
Apr 05 2020
On Sunday, 5 April 2020 at 20:54:03 UTC, Meta wrote:On Sunday, 5 April 2020 at 20:31:15 UTC, Timon Gehr wrote:No. the in contract was already a pain in the butt.On 05.04.20 14:11, Stefan Koch wrote:We likely get the shorthand version for free as well: string generateMixin(...) in(__ctfe) { ... }[...]Make sure it works with `in` contracts: string generateMixin(string[] params)in{ assert(__ctfe); }do{ .... more code .... } (The plain assertion slightly hurts my eyes, because if it fails, that failure would be attributable to the GenerateMixin function, whereas with the `in` contract it is clear that the caller is at fault.)
Apr 05 2020
On Sunday, 5 April 2020 at 22:12:02 UTC, Stefan Koch wrote:On Sunday, 5 April 2020 at 20:54:03 UTC, Meta wrote:That IS an in contract. idk about the implementation but from the user level this is identical to in { assert(__ctfe);}We likely get the shorthand version for free as well: string generateMixin(...) in(__ctfe) { ... }No. the in contract was already a pain in the butt.
Apr 05 2020
On 06.04.20 00:12, Stefan Koch wrote:On Sunday, 5 April 2020 at 20:54:03 UTC, Meta wrote:I don't understand how you would implement it in a way where the above does not work. Have you tested it? I am literally rewriting `in(__ctfe)` to `in{ assert(__ctfe); }` in the parser: https://github.com/dlang/dmd/blob/master/src/dmd/parse.d#L5060On Sunday, 5 April 2020 at 20:31:15 UTC, Timon Gehr wrote:No. the in contract was already a pain in the butt.On 05.04.20 14:11, Stefan Koch wrote:We likely get the shorthand version for free as well: string generateMixin(...) in(__ctfe) { ... }[...]Make sure it works with `in` contracts: string generateMixin(string[] params)in{ assert(__ctfe); }do{ .... more code .... } (The plain assertion slightly hurts my eyes, because if it fails, that failure would be attributable to the GenerateMixin function, whereas with the `in` contract it is clear that the caller is at fault.)
Apr 05 2020
On Monday, 6 April 2020 at 01:28:19 UTC, Timon Gehr wrote:I don't understand how you would implement it in a way where the above does not work. Have you tested it? I am literally rewriting `in(__ctfe)` to `in{ assert(__ctfe); }` in the parser: https://github.com/dlang/dmd/blob/master/src/dmd/parse.d#L5060I see. Well in that case it'll work out of the box. Although it does make me shudder to change the Tree in the parser in such a way. When was this merged?
Apr 05 2020
On 06.04.20 04:25, Stefan Koch wrote:On Monday, 6 April 2020 at 01:28:19 UTC, Timon Gehr wrote:For no reason at all. It's the appropriate place to expand simple short-hand notation, e.g., see template functions. It's just good engineering. Let's consider the evidence: What you expected to be the case: - `in(expr)` is a special kind of construct in the AST, burdening the entire compiler code base from frontend to backend. - `in{ assert(__ctfe); }` and `in(__ctfe)` have diverging behavior, a unfortunate development caused by butt pain. What was actually the case: - `in(expr)` is simple shorthand notation and is treated by the compiler precisely like `in{ assert(__ctfe); }` - `in(__ctfe)` works precisely like `in{ assert(__ctfe); }` even after the latter has been special-cased. You might want to recalibrate your guts. :PI don't understand how you would implement it in a way where the above does not work. Have you tested it? I am literally rewriting `in(__ctfe)` to `in{ assert(__ctfe); }` in the parser: https://github.com/dlang/dmd/blob/master/src/dmd/parse.d#L5060I see. Well in that case it'll work out of the box. Although it does make me shudder to change the Tree in the parser in such a way.When was this merged?Just when it should have been, right after the corresponding DIP was accepted.
Apr 05 2020
On Monday, 6 April 2020 at 03:11:41 UTC, Timon Gehr wrote:On 06.04.20 04:25, Stefan Koch wrote:I don't mind the what. I just mind the when. But it's not a big deal either way. I would have done it in sema.[...]For no reason at all. It's the appropriate place to expand simple short-hand notation, e.g., see template functions. [...]
Apr 06 2020
On Monday, 6 April 2020 at 07:33:19 UTC, Stefan Koch wrote:On Monday, 6 April 2020 at 03:11:41 UTC, Timon Gehr wrote:Offtopic. This triggers me, so a quick response: the tree rewriting that happens all over the place in the compiler frontend is very problematic with anything that has to report back to the user and more: debug location information, error reporting, coverage reporting, syntax highlighting, source formatting, etc., etc. [*] -Johan [*] As an example, even the harmless looking replacement of __FILE__ by the parser, turns out to be very problematic for LDC for deterministically generating symbol names (linking) when combined with crossmodule inlining :(On 06.04.20 04:25, Stefan Koch wrote:I don't mind the what. I just mind the when. But it's not a big deal either way. I would have done it in sema.[...]For no reason at all. It's the appropriate place to expand simple short-hand notation, e.g., see template functions. [...]
Apr 06 2020
On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:Hi Guys, I am currently working on speeding up dmd. In the presence of templates and ctfe. and one thing that stood out is that we do codegen for symbols which are never used. (and hopefully eliminated by a smart linker but eh ...) [...]Wouldn't it be easier to skip codegen for private functions that are never called from non CTFE contexts?
Apr 06 2020
On Monday, 6 April 2020 at 10:14:24 UTC, Atila Neves wrote:On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:Easier from the user-perspective yes. From the compiler perspective, That's another step which may take quite a while to do correctly. The easy thing would be (Essentially an (N*M) loop over all calls and functions), which I doubt will help compile-times much. For now assert(__ctfe); enables people to manually mark their ctfe-only, functions.Hi Guys, I am currently working on speeding up dmd. In the presence of templates and ctfe. and one thing that stood out is that we do codegen for symbols which are never used. (and hopefully eliminated by a smart linker but eh ...) [...]Wouldn't it be easier to skip codegen for private functions that are never called from non CTFE contexts?
Apr 06 2020
On Monday, 6 April 2020 at 13:41:52 UTC, Stefan Koch wrote:On Monday, 6 April 2020 at 10:14:24 UTC, Atila Neves wrote:Where N and M are all calls and private functions in one module, not all code in a project.On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:Easier from the user-perspective yes. From the compiler perspective, That's another step which may take quite a while to do correctly. The easy thing would be (Essentially an (N*M) loop over all calls and functions),[...]Wouldn't it be easier to skip codegen for private functions that are never called from non CTFE contexts?For now assert(__ctfe); enables people to manually mark their ctfe-only, functions.What about `in(__ctfe)` instead?
Apr 06 2020
On Monday, 6 April 2020 at 13:49:19 UTC, Atila Neves wrote:On Monday, 6 April 2020 at 13:41:52 UTC, Stefan Koch wrote:in (__ctfe) is already supported.On Monday, 6 April 2020 at 10:14:24 UTC, Atila Neves wrote:Where N and M are all calls and private functions in one module, not all code in a project.On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:Easier from the user-perspective yes. From the compiler perspective, That's another step which may take quite a while to do correctly. The easy thing would be (Essentially an (N*M) loop over all calls and functions),[...]Wouldn't it be easier to skip codegen for private functions that are never called from non CTFE contexts?For now assert(__ctfe); enables people to manually mark their ctfe-only, functions.What about `in(__ctfe)` instead?
Apr 06 2020
On Monday, 6 April 2020 at 13:49:19 UTC, Atila Neves wrote:On Monday, 6 April 2020 at 13:41:52 UTC, Stefan Koch wrote:It was already explained, this will expand to the same code, so yes, both will work.For now assert(__ctfe); enables people to manually mark their ctfe-only, functions.What about `in(__ctfe)` instead?
Apr 06 2020
On Monday, 6 April 2020 at 14:14:48 UTC, Dominikus Dittes Scherkl wrote:On Monday, 6 April 2020 at 13:49:19 UTC, Atila Neves wrote:Well technically I had to do a bit of work for InContracts ("Requires" in dmd lingo), because for them you need to unwrap the scopeStatements.On Monday, 6 April 2020 at 13:41:52 UTC, Stefan Koch wrote:It was already explained, this will expand to the same code, so yes, both will work.For now assert(__ctfe); enables people to manually mark their ctfe-only, functions.What about `in(__ctfe)` instead?
Apr 06 2020
Am Mon, 06 Apr 2020 13:49:19 +0000 schrieb Atila Neves:On Monday, 6 April 2020 at 13:41:52 UTC, Stefan Koch wrote:In fact, you can't do that in current D. I thought about it some time ago, consider this valid D code: --------------------------- module foo; private void privateFunc() {} public void publicTemplate(T)() { privateFunc(); } --------------------------- Let's say I compile module foo into libfoo. libfoo internally never uses publicTemplate. An external user instantiates publicTemplate ==> privateFunc needs to be emitted in libfoo. Now you can't even check that privateFunc is never called, cause you can't analyze the template without instantiating it. And in general, you can't instantiate it without knowing the template instance type parameters. (In this simple example you might think this should work. But just imagine that I can pass in a type with an enum string member, which I can then mixin in the template, ....) Generally the only way to solve this seems to finally implement export properly, as it was proposed years ago. Then privateFunc should be flagged export (needed for windows DLL support and linux .so selective exports anyway) and you could probably strip uncalled, non-exported private functions. TLDR: It's certainly not easy to implement. -- JohannesOn Monday, 6 April 2020 at 10:14:24 UTC, Atila Neves wrote:Where N and M are all calls and private functions in one module, not all code in a project.On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:Easier from the user-perspective yes. From the compiler perspective, That's another step which may take quite a while to do correctly. The easy thing would be (Essentially an (N*M) loop over all calls and functions),[...]Wouldn't it be easier to skip codegen for private functions that are never called from non CTFE contexts?
Apr 07 2020
On 2020-04-07 13:41, Johannes Pfau wrote:Am Mon, 06 Apr 2020 13:49:19 +0000 schrieb Atila Neves:You can also bypass "private" using __traits(getMemeber) or using an extern(D) declaration. -- /Jacob CarlborgOn Monday, 6 April 2020 at 13:41:52 UTC, Stefan Koch wrote:In fact, you can't do that in current D. I thought about it some time ago, consider this valid D code: --------------------------- module foo; private void privateFunc() {} public void publicTemplate(T)() { privateFunc(); } --------------------------- Let's say I compile module foo into libfoo. libfoo internally never uses publicTemplate. An external user instantiates publicTemplate ==> privateFunc needs to be emitted in libfoo. Now you can't even check that privateFunc is never called, cause you can't analyze the template without instantiating it. And in general, you can't instantiate it without knowing the template instance type parameters. (In this simple example you might think this should work. But just imagine that I can pass in a type with an enum string member, which I can then mixin in the template, ....) Generally the only way to solve this seems to finally implement export properly, as it was proposed years ago. Then privateFunc should be flagged export (needed for windows DLL support and linux .so selective exports anyway) and you could probably strip uncalled, non-exported private functions. TLDR: It's certainly not easy to implement.On Monday, 6 April 2020 at 10:14:24 UTC, Atila Neves wrote:Where N and M are all calls and private functions in one module, not all code in a project.On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:Easier from the user-perspective yes. From the compiler perspective, That's another step which may take quite a while to do correctly. The easy thing would be (Essentially an (N*M) loop over all calls and functions),[...]Wouldn't it be easier to skip codegen for private functions that are never called from non CTFE contexts?
Apr 07 2020
On 4/6/2020 3:14 AM, Atila Neves wrote:Wouldn't it be easier to skip codegen for private functions that are never called from non CTFE contexts?There's no reason the CTFE-only function can't be global.
Apr 06 2020
On Tuesday, 7 April 2020 at 06:53:18 UTC, Walter Bright wrote:On 4/6/2020 3:14 AM, Atila Neves wrote:No, there isn't. But in my experience nearly all functions I write that are only ever called from CTFE returning a string to be mixed in are private.Wouldn't it be easier to skip codegen for private functions that are never called from non CTFE contexts?There's no reason the CTFE-only function can't be global.
Apr 07 2020
On Tuesday, 7 April 2020 at 09:16:34 UTC, Atila Neves wrote:On Tuesday, 7 April 2020 at 06:53:18 UTC, Walter Bright wrote:I've done it both ways. If it can be accomplished easily enough might as well support both equally.There's no reason the CTFE-only function can't be global.No, there isn't. But in my experience nearly all functions I write that are only ever called from CTFE returning a string to be mixed in are private.
Apr 07 2020
Sounds ok to me, as long as the assert(__ctfe) is the first statement in the function body. Though I would check the linker map file to see if the linker didn't already omit functions that were never called.
Apr 06 2020
On Tuesday, 7 April 2020 at 06:55:59 UTC, Walter Bright wrote:Sounds ok to me, as long as the assert(__ctfe) is the first statement in the function body. Though I would check the linker map file to see if the linker didn't already omit functions that were never called.In order to support contracts we need to go through all the statements in the merged contract .... but I can split that out.
Apr 07 2020
On 4/7/2020 12:33 AM, Stefan Koch wrote:On Tuesday, 7 April 2020 at 06:55:59 UTC, Walter Bright wrote:You could move it up earlier in the semantic analysis. When semantic analysis starts, simply check the first statement, and set a flag "no code gen" in the FuncDeclaration.Sounds ok to me, as long as the assert(__ctfe) is the first statement in the function body. Though I would check the linker map file to see if the linker didn't already omit functions that were never called.In order to support contracts we need to go through all the statements in the merged contract .... but I can split that out.
Apr 07 2020
On Tuesday, 7 April 2020 at 06:55:59 UTC, Walter Bright wrote:Sounds ok to me, as long as the assert(__ctfe) is the first statement in the function body. Though I would check the linker map file to see if the linker didn't already omit functions that were never called.I think the problem with relying on the linker is that the user still pays with longer compile times for codegen that isn't needed.
Apr 07 2020
On 4/7/2020 2:17 AM, Atila Neves wrote:I think the problem with relying on the linker is that the user still pays with longer compile times for codegen that isn't needed.True
Apr 07 2020
On 4/7/20 5:17 AM, Atila Neves wrote:On Tuesday, 7 April 2020 at 06:55:59 UTC, Walter Bright wrote:Isn't there an issue for better C as well? If a function can't be compiled in betterC but is valid for CTFE, then this could be a potential solution. I don't know how this works today. -SteveSounds ok to me, as long as the assert(__ctfe) is the first statement in the function body. Though I would check the linker map file to see if the linker didn't already omit functions that were never called.I think the problem with relying on the linker is that the user still pays with longer compile times for codegen that isn't needed.
Apr 07 2020
On Tuesday, 7 April 2020 at 21:11:11 UTC, Steven Schveighoffer wrote:On 4/7/20 5:17 AM, Atila Neves wrote:Good question, me neither.On Tuesday, 7 April 2020 at 06:55:59 UTC, Walter Bright wrote:Isn't there an issue for better C as well? If a function can't be compiled in betterC but is valid for CTFE, then this could be a potential solution. I don't know how this works today. -SteveSounds ok to me, as long as the assert(__ctfe) is the first statement in the function body. Though I would check the linker map file to see if the linker didn't already omit functions that were never called.I think the problem with relying on the linker is that the user still pays with longer compile times for codegen that isn't needed.
Apr 08 2020
Am Wed, 08 Apr 2020 09:53:24 +0000 schrieb Atila Neves:The answer is simple. It simply does not work today ;-) -- JohannesIsn't there an issue for better C as well? If a function can't be compiled in betterC but is valid for CTFE, then this could be a potential solution. I don't know how this works today. -SteveGood question, me neither.
Apr 08 2020
Am Mon, 06 Apr 2020 23:55:59 -0700 schrieb Walter Bright:Sounds ok to me, as long as the assert(__ctfe) is the first statement in the function body. Though I would check the linker map file to see if the linker didn't already omit functions that were never called.Very nice work, Stefan! This has multiple benefits which have not been mentioned yet: Yes, the linker might eliminate such functions. In some cases it can't do that though, most importantly when building shared libraries. So you may end up with useless mixin helpers in shared libraries. Now when we ever get a proper export implementation, the linker might be able to remove these as well. As mentioned earlier, no doing codegen might reduce compile times. I guess this can be more important for GDC and LDC than for DMD, as we spent quite some time in backend optimizer phases. I remember Mike doing template heavy embedded stuff which lead to compile times of minutes for a hello world with gdc. And IIRC the main issue was the optimizer working on hundreds of unused template instances. And the most important thing: This will vastly improve betterC / nogc code: -------------------- string generateMixin(T)(string b) { assert(__ctfe); return T.stringof ~ " " ~ b ~ ";"; } void main() nogc { mixin(generateMixin!string("b")); } -------------------- Here emitting generateMixin means that at least some of the array appending infrastructure needs to be there. If we don't emit the function at all, we can probably get rid of all related issues. However, to also enable these benefits for betterC and not only for nogc, we have to disable the betterC semantic check for such CTFE-only functions: test.d(4): Error: array concatenation of expression "string " ~ b ~ ";" requires the GC which is not available with -betterC Stefan can you add that to your PR? Also a comment regarding ctfe UDA vs assert(__ctfe): Although ctfe adds clutter to function signatures, that actually has it's benefits. With ctfe it would be trivial to check that ctfe functions are only called from other ctfe functions or a CTFE context instead of letting users run into linker errors. Also the information would be available early, I'm not sure if the check in semantic3 might be too late for some things (e.g. to disable betterC checks)? This is especially a problem if you link to external libraries where you don't have source code: The .di and docs could only include the signature and the compiler and user just can't know that this is a ctfe-only function. OTOH it doesn't make sense to have only the signature of such a function, so you'd probably include the function body for CTFE in the .di file anyway. But this would still require the compiler to do an complete semantic on all imported modules, only to warn the user if he tried to use a ctfe function in non-ctfe context. So I guess all things considered I'd prefer ctfe. But as long as whatever syntax is chosen works with -betterC, I'll be very happy either way :-) -- Johannes
Apr 07 2020
On Tuesday, 7 April 2020 at 11:32:27 UTC, Johannes Pfau wrote:And the most important thing: This will vastly improve betterC / nogc code: -------------------- string generateMixin(T)(string b) { assert(__ctfe); return T.stringof ~ " " ~ b ~ ";"; } void main() nogc { mixin(generateMixin!string("b")); } --------------------I can confirm with the patch there are no template-instances in the object file with patch: 0000000000000000 R _D6t_ctfe12__ModuleInfoZ U _d_dso_registry 0000000000000000 W _Dmain U _Dmain U _d_run_main U _GLOBAL_OFFSET_TABLE_ 0000000000000000 W main U _main U __start_minfo U __stop_minfo without patch: U _D12TypeInfo_Aya6__initZ 0000000000000000 R _D6t_ctfe12__ModuleInfoZ 0000000000000000 W _D6t_ctfe__T13generateMixinTAyaZQuFNaNbNfQnZQq U _d_arraycatnTX U _d_assertp U _d_dso_registry 0000000000000000 W _Dmain U _Dmain U _d_run_main U _GLOBAL_OFFSET_TABLE_ 0000000000000000 W main U _main U __start_minfo U __stop_minfo 0000000000000000 r _TMP0 0000000000000009 r _TMP1 000000000000000b r _TMP2
Apr 07 2020
On Tuesday, 7 April 2020 at 12:09:48 UTC, Stefan Koch wrote:I can confirm with the patch there are no template-instances in the object fileVery cool! Thanks.
Apr 07 2020
Am Tue, 07 Apr 2020 12:09:48 +0000 schrieb Stefan Koch:On Tuesday, 7 April 2020 at 11:32:27 UTC, Johannes Pfau wrote:The example above actually already compiles with -betterC, as the check is done in codegen phase! But some betterC checks seem to be done in semantic. This doesn't work yet: ------------------------ string generateMixin(T)(string b) { assert(__ctfe); return typeid(T).stringof ~ " " ~ b ~ ";"; } void main() nogc { mixin(generateMixin!string("b")); } ------------------------ dmd -betterC test.d -c test.d(4): Error: TypeInfo cannot be used with -betterC -- JohannesAnd the most important thing: This will vastly improve betterC / nogc code: -------------------- string generateMixin(T)(string b) { assert(__ctfe); return T.stringof ~ " " ~ b ~ ";"; } void main() nogc { mixin(generateMixin!string("b")); } --------------------I can confirm with the patch there are no template-instances in the object file
Apr 07 2020
On 4/7/20 12:53 PM, Johannes Pfau wrote:The example above actually already compiles with -betterC, as the check is done in codegen phase! But some betterC checks seem to be done in semantic. This doesn't work yet: ------------------------ string generateMixin(T)(string b) { assert(__ctfe); return typeid(T).stringof ~ " " ~ b ~ ";"; } void main() nogc { mixin(generateMixin!string("b")); } ------------------------ dmd -betterC test.d -c test.d(4): Error: TypeInfo cannot be used with -betterCIronically, ctfe can't deal with TypeInfo today. In the past, the issue was for functions that use TypeInfo is that the non-CTFE branch uses TypeInfo, and that can't be used in betterC, but the CTFE branch doesn't use TypeInfo, but the compiler wants to build the whole function. So while this is still a problem, I don't think this fix will change that. -Steve
Apr 07 2020
Am Tue, 07 Apr 2020 17:13:54 -0400 schrieb Steven Schveighoffer:On 4/7/20 12:53 PM, Johannes Pfau wrote:I'm not sure what exactly you're referring to, but this code compiles perfactly fine: -------------------------- string generateMixin(T)(string b) { assert(__ctfe); return "auto a = " ~typeid(T).stringof ~ ";"; } void main() nogc { mixin(generateMixin!string("b")); pragma(msg, generateMixin!string("b")); } -------------------------- But it does not copile with -betterC. The point here is that the "Error: TypeInfo cannot be used with -betterC" message does not apply to CTFE- only functions, so this PR should be able to disable the check. My primary fear here is that the current implementation checks the function too late in semantic and therefore such checks (or the "ensure no non-ctfe function calls ctfe-only functions" check are much more difficult to implement than they should be. Using a pragma or attribute would easily solve this. Maybe you'd have to introduce something analog to "safetyInProgress" which is "ctfeOnlyInProgress" to make this assert(__ctfe) detection fully usable? But I think this adds way to much complexity. Even right now, the code of the PR could probably be reduced by 1/2 when just using a pragma. -- JohannesThe example above actually already compiles with -betterC, as the check is done in codegen phase! But some betterC checks seem to be done in semantic. This doesn't work yet: ------------------------ string generateMixin(T)(string b) { assert(__ctfe); return typeid(T).stringof ~ " " ~ b ~ ";"; } void main() nogc { mixin(generateMixin!string("b")); } ------------------------ dmd -betterC test.d -c test.d(4): Error: TypeInfo cannot be used with -betterCIronically, ctfe can't deal with TypeInfo today. In the past, the issue was for functions that use TypeInfo is that the non-CTFE branch uses TypeInfo, and that can't be used in betterC, but the CTFE branch doesn't use TypeInfo, but the compiler wants to build the whole function. So while this is still a problem, I don't think this fix will change that. -Steve
Apr 08 2020
On Wednesday, 8 April 2020 at 07:09:11 UTC, Johannes Pfau wrote:Am Tue, 07 Apr 2020 17:13:54 -0400 schrieb Steven Schveighoffer:The detection of assert __ctfe in the function body _can_ be done very early in the process I do not want to introduce a pragma or magic annotatation. When existing the language is perfectly able to express (only runs at ctfe). Also the PR I have open is _only_ for that. I or someone else, might write code which does the detection earlier and then disables betterC checks, but this is only about turning off codegen.On 4/7/20 12:53 PM, Johannes Pfau wrote:I'm not sure what exactly you're referring to, but this code compiles perfactly fine: -------------------------- string generateMixin(T)(string b) { assert(__ctfe); return "auto a = " ~typeid(T).stringof ~ ";"; } void main() nogc { mixin(generateMixin!string("b")); pragma(msg, generateMixin!string("b")); } -------------------------- But it does not copile with -betterC. The point here is that the "Error: TypeInfo cannot be used with -betterC" message does not apply to CTFE- only functions, so this PR should be able to disable the check. My primary fear here is that the current implementation checks the function too late in semantic and therefore such checks (or the "ensure no non-ctfe function calls ctfe-only functions" check are much more difficult to implement than they should be. Using a pragma or attribute would easily solve this. Maybe you'd have to introduce something analog to "safetyInProgress" which is "ctfeOnlyInProgress" to make this assert(__ctfe) detection fully usable? But I think this adds way to much complexity. Even right now, the code of the PR could probably be reduced by 1/2 when just using a pragma.[...]Ironically, ctfe can't deal with TypeInfo today. In the past, the issue was for functions that use TypeInfo is that the non-CTFE branch uses TypeInfo, and that can't be used in betterC, but the CTFE branch doesn't use TypeInfo, but the compiler wants to build the whole function. So while this is still a problem, I don't think this fix will change that. -Steve
Apr 08 2020
On Wednesday, 8 April 2020 at 08:42:52 UTC, Stefan Koch wrote:When existing the language is perfectly able to express (only runs at ctfe).assert(__ctfe) does not express that you STATICALLY know it only runs at ctfe, it is a RUNTIME error and it is impossible to statically decide whether the function may actually get called outside ctfe context.
Apr 08 2020
On Wednesday, 8 April 2020 at 09:11:45 UTC, Dennis wrote:On Wednesday, 8 April 2020 at 08:42:52 UTC, Stefan Koch wrote:The only reason why I used assert (__ctfe) not static assert (__ctfe) is because that's impossible to express. since __ctfe is a magic runtime variable that's hardwired to be zero in the non-ctfe case.When existing the language is perfectly able to express (only runs at ctfe).assert(__ctfe) does not express that you STATICALLY know it only runs at ctfe, it is a RUNTIME error and it is impossible to statically decide whether the function may actually get called outside ctfe context.
Apr 08 2020
On Wednesday, 8 April 2020 at 09:48:25 UTC, Stefan Koch wrote:The only reason why I used assert (__ctfe) not static assert (__ctfe) is because that's impossible to express. since __ctfe is a magic runtime variable that's hardwired to be zero in the non-ctfe case.Indeed, and that should make you think how you can properly express that instead of adding special cases to established language concepts making them mean an entirely different thing. Imagine if D could not express quick sort, so programmers just use bubble sort instead out of necessity. Then to fix that, you let the compiler detect a common bubble-sort implementation, and replace it with a quick-sort implementation. It is backwards-compatible and automatically works with existing code. What a fix! Except even the slightest deviation of that pattern will break the optimization. Also the quick-sort implementation is not stable unlike bubble sort, so the behavior is actually different making this an illegal optimization. What a hack! Problems like this should be attacked at the root. This assert(__ctfe) hack may fix one thing in the short-term, but you gain a lot of technical debt. Next thing you'll stumble upon this: ``` import core.stdc.stdlib; int* newIntPtr() nogc { if (__ctfe) { return new int(); // Error: cannot use new in nogc function } else { return cast(int*) malloc(4); } } ``` What now, another hack? Or should we finally think of something to make __ctfe work with `static if` / `static assert` proper?
Apr 08 2020
On Wednesday, 8 April 2020 at 10:27:02 UTC, Dennis wrote:What now, another hack? Or should we finally think of something to make __ctfe work with `static if` / `static assert` proper?I have tried doing that for a long time and gave up. the problem is that static if and static assert get done before ctfe. and therefore would always see the __ctfe being false. A language which only allows you to express bubble-sort may have a good reason for that limitation. Though I suspect it would come down to religious believes in mathematical concepts.
Apr 08 2020
On Wednesday, 8 April 2020 at 10:47:07 UTC, Stefan Koch wrote:A language which only allows you to express bubble-sort may have a good reason for that limitation. Though I suspect it would come down to religious believes in mathematical concepts.Let me be clear in case you're implying my critique is for the sake of satisfying some mathematical principle. I'm objecting this because *actual D users* constantly complain about D garnering more and more half-baked features that don't integrate well with the rest of the language, and this is like the epitome of that. It does not work at all with `version`, `mixin`, constant folding among others.
Apr 09 2020
On 08.04.20 12:27, Dennis wrote:What now, another hack? Or should we finally think of something to make __ctfe work with `static if` / `static assert` proper?It's obvious how to make that work, but is it really worth the effort and compile time overhead? You'd have to perform semantic analysis twice for each function.
Apr 09 2020
On Thursday, 9 April 2020 at 09:30:14 UTC, Timon Gehr wrote:On 08.04.20 12:27, Dennis wrote:That could be a good POC implementation to start with, from there we can see how far it can be optimized. However, what I meant with that statement was not that we literally should support `static if (__ctfe)`, just some way of actually statically recognizing ctfe-only code. pragma(ctfe) looks like a promising candidate to me: https://github.com/dlang/dmd/pull/11014What now, another hack? Or should we finally think of something to make __ctfe work with `static if` / `static assert` proper?It's obvious how to make that work, but is it really worth the effort and compile time overhead? You'd have to perform semantic analysis twice for each function.
Apr 09 2020
On Wednesday, 8 April 2020 at 09:48:25 UTC, Stefan Koch wrote:On Wednesday, 8 April 2020 at 09:11:45 UTC, Dennis wrote:This may be a naive suggestion, but how hard would it be to make version(ctfe) work? version (ctfe) string generateMixin(...) { ... } Using version means you would be able to know earlier whether a function is ctfe-only, but I'm not sure how you could propogate that information through the rest of semantic-analysis and what effects that could have.On Wednesday, 8 April 2020 at 08:42:52 UTC, Stefan Koch wrote:The only reason why I used assert (__ctfe) not static assert (__ctfe) is because that's impossible to express. since __ctfe is a magic runtime variable that's hardwired to be zero in the non-ctfe case.When existing the language is perfectly able to express (only runs at ctfe).assert(__ctfe) does not express that you STATICALLY know it only runs at ctfe, it is a RUNTIME error and it is impossible to statically decide whether the function may actually get called outside ctfe context.
Apr 08 2020
Am Wed, 08 Apr 2020 19:16:15 +0000 schrieb Jonathan Marler:On Wednesday, 8 April 2020 at 09:48:25 UTC, Stefan Koch wrote:I'd guess very hard. To be consistent with the rest of the language, you then have to support this: void foo() { version (ctfe) { } else { } } You can end up with two completely different function implementations. And you can do this at top-level as well, where you have the same function in version(ctfe) and in the else block. Maybe you can somehow cheat and simplify this. But in the most general case, you'd have to keep two versions of the AST of each function. -- JohannesOn Wednesday, 8 April 2020 at 09:11:45 UTC, Dennis wrote:This may be a naive suggestion, but how hard would it be to make version(ctfe) work? version (ctfe) string generateMixin(...) { ... } Using version means you would be able to know earlier whether a function is ctfe-only, but I'm not sure how you could propogate that information through the rest of semantic-analysis and what effects that could have.On Wednesday, 8 April 2020 at 08:42:52 UTC, Stefan Koch wrote:The only reason why I used assert (__ctfe) not static assert (__ctfe) is because that's impossible to express. since __ctfe is a magic runtime variable that's hardwired to be zero in the non-ctfe case.When existing the language is perfectly able to express (only runs at ctfe).assert(__ctfe) does not express that you STATICALLY know it only runs at ctfe, it is a RUNTIME error and it is impossible to statically decide whether the function may actually get called outside ctfe context.
Apr 08 2020
On Wednesday, April 8, 2020 3:11:45 AM MDT Dennis via Digitalmars-d wrote:On Wednesday, 8 April 2020 at 08:42:52 UTC, Stefan Koch wrote:Sure, but since you're asserting that it should never run except during CTFE, turning that into a compiler or linker error shouldn't be a problem. It's about as clear a case as you can get where the compiler can effectively turn a runtime condition into a compile-time one, because it has enough information to do that optimization, and if assert(__ctfe) is used where it shouldn't be, then it will just result in an error when compiling/linking your program instead of at runtime. Insisting that the compiler not do that optimization doesn't really buy us anything, and having it do that optimization could allow us to reduce compilation times in code with a lot of CTFE-only functions. It would arguably be cleaner if __ctfe were done in a way that it were a static condition rather than a runtime one (and thus static assert could be used instead), but that's not how it works, and from what I understand of how CTFE in general works, it's highly unlikely that that will ever change. - Jonathan M DavisWhen existing the language is perfectly able to express (only runs at ctfe).assert(__ctfe) does not express that you STATICALLY know it only runs at ctfe, it is a RUNTIME error and it is impossible to statically decide whether the function may actually get called outside ctfe context.
Apr 08 2020
On Wednesday, 8 April 2020 at 23:45:43 UTC, Jonathan M Davis wrote:because it has enough information to do that optimization, and if assert(__ctfe) is used where it shouldn't be, then it will just result in an error when compiling/linking your program instead of at runtime.It's not an optimization, it is a breaking change that can turn valid code into compile errors or linker errors. Minimal examples are: ``` int ctfeOnly() { assert(__ctfe); return 3; } int alsoCtfeOnly() { version(all) { assert(__ctfe); // ctfe detection is defeated by the slightest deviation return ctfeOnly(); } } ``` This will become a compile error. ``` immutable ctfeOnly = function int() { assert(__ctfe); return 3; }; ``` This will become a linker error.It would arguably be cleaner if __ctfe were done in a way that it were a static condition rather than a runtime one (and thus static assert could be used instead), but that's not how it works, and from what I understand of how CTFE in general works, it's highly unlikely that that will ever change.I don't agree there. First of all, this seems like an implementation difficulty, not a fundamental limitation. Second of all, there are plenty of alternatives to consider, such as version(__ctfe) or pragma(ctfe). Johannes Pfau is working on the latter right now: https://github.com/dlang/dmd/pull/11014
Apr 09 2020
On Wed, Apr 08, 2020 at 05:45:43PM -0600, Jonathan M Davis via Digitalmars-d wrote: [...]It would arguably be cleaner if __ctfe were done in a way that it were a static condition rather than a runtime one (and thus static assert could be used instead), but that's not how it works, and from what I understand of how CTFE in general works, it's highly unlikely that that will ever change.[...] Yeah, static assert is run at template expansion time, which comes before CTFE, so __ctfe cannot be evaluated by static assert: https://wiki.dlang.org/User:Quickfur/Compile-time_vs._compile-time T -- WINDOWS = Will Install Needless Data On Whole System -- CompuMan
Apr 08 2020
Am Wed, 08 Apr 2020 08:42:52 +0000 schrieb Stefan Koch:The important point is that we do not bake in semantics now which might turn out to cause problems later. If we can do the assert detection before all betterC checking, nogc checking, and related checks, this is fine. But it should not be an afterthought, we should really be pretty sure that this will not cause issues later on and that this integrates well with all other language features. Especially betterC, nogc (if you have a nogc: at module top, do you want to still enforce GC checks in CTFE only code, ...) -- JohannesMy primary fear here is that the current implementation checks the function too late in semantic and therefore such checks (or the "ensure no non-ctfe function calls ctfe-only functions" check are much more difficult to implement than they should be. Using a pragma or attribute would easily solve this. Maybe you'd have to introduce something analog to "safetyInProgress" which is "ctfeOnlyInProgress" to make this assert(__ctfe) detection fully usable? But I think this adds way to much complexity. Even right now, the code of the PR could probably be reduced by 1/2 when just using a pragma.The detection of assert __ctfe in the function body _can_ be done very early in the process I do not want to introduce a pragma or magic annotatation. When existing the language is perfectly able to express (only runs at ctfe). Also the PR I have open is _only_ for that. I or someone else, might write code which does the detection earlier and then disables betterC checks, but this is only about turning off codegen.
Apr 08 2020
On 4/8/20 3:09 AM, Johannes Pfau wrote:Am Tue, 07 Apr 2020 17:13:54 -0400 schrieb Steven Schveighoffer:I misread your example! I thought you were doing typeid(T).toString. I had to fix an issue very recently that was similar to this. TypeInfo does not work inside ctfe, but here you aren't actually using the TypeInfo object. If you switch to typeid(T).toString, even without -betterC you get: Error: static variable typeid(string) cannot be read at compile time But your example is indeed a bug with betterC. But even if that was fixed, the code would still not work. It seems more like a diagnostic error: return "auto a = typeid(" ~ T.stringof ~ ");"; This is equivalent to your code and will work in betterC, but the mixin of it won't.On 4/7/20 12:53 PM, Johannes Pfau wrote:I'm not sure what exactly you're referring to, but this code compiles perfactly fine: -------------------------- string generateMixin(T)(string b) { assert(__ctfe); return "auto a = " ~typeid(T).stringof ~ ";"; } void main() nogc { mixin(generateMixin!string("b")); pragma(msg, generateMixin!string("b")); } --------------------------The example above actually already compiles with -betterC, as the check is done in codegen phase! But some betterC checks seem to be done in semantic. This doesn't work yet: ------------------------ string generateMixin(T)(string b) { assert(__ctfe); return typeid(T).stringof ~ " " ~ b ~ ";"; } void main() nogc { mixin(generateMixin!string("b")); } ------------------------ dmd -betterC test.d -c test.d(4): Error: TypeInfo cannot be used with -betterCIronically, ctfe can't deal with TypeInfo today. In the past, the issue was for functions that use TypeInfo is that the non-CTFE branch uses TypeInfo, and that can't be used in betterC, but the CTFE branch doesn't use TypeInfo, but the compiler wants to build the whole function. So while this is still a problem, I don't think this fix will change that.But it does not copile with -betterC. The point here is that the "Error: TypeInfo cannot be used with -betterC" message does not apply to CTFE- only functions, so this PR should be able to disable the check.In fact, there is a further error that TypeInfo isn't being used AT ALL, and it's still complaining.My primary fear here is that the current implementation checks the function too late in semantic and therefore such checks (or the "ensure no non-ctfe function calls ctfe-only functions" check are much more difficult to implement than they should be. Using a pragma or attribute would easily solve this.This is a legitimate concern. Indeed, it might not fix this issue just to not emit the code to the binary. -Steve
Apr 08 2020
Am Wed, 08 Apr 2020 09:26:36 -0400 schrieb Steven Schveighoffer:I've posted a proof-of-concept PR using pragma(ctfe) here: https://github.com/dlang/dmd/pull/11014 Unlike the `assert(__ctfe)` check, this is done very early in the semantic analysis. I added support to bypass all -betterC checks I could find in the DMD source code. If one is missing, it should be trivial to add. I've also added examples to the tests in the PR. I also tried to backport the commit which introduces the betterC bypass to Stefan's PR. But as expected it does not work, as the assert detection is done too late. I'm not saying that we must go for pragma(ctfe), but whatever implementation we merge, it should at least support those tests as well. Especially considering the pragma implementation is also way less complex. Another thing we could think about is how to handle this code: nogc: pragma(ctfe) string mixinHelper2(string a) { return "int " ~ a ~ ";"; } void main() nogc { mixin(mixinHelper("a")); } I'd probably disable nogc checks in ctfe-only functions for convenience. But I guess that is debatable. -- JohannesMy primary fear here is that the current implementation checks the function too late in semantic and therefore such checks (or the "ensure no non-ctfe function calls ctfe-only functions" check are much more difficult to implement than they should be. Using a pragma or attribute would easily solve this.This is a legitimate concern. Indeed, it might not fix this issue just to not emit the code to the binary. -Steve
Apr 08 2020
On 2020-04-05 14:11, Stefan Koch wrote:Hi Guys, I am currently working on speeding up dmd. In the presence of templates and ctfe. and one thing that stood out is that we do codegen for symbols which are never used. (and hopefully eliminated by a smart linker but eh ...) I've seen the following pattern in the wild. string GenerateMixin(string[] params) { assert(__ctfe); .... more code .... } that means if we see assert(__ctfe) inside the outermost scope of a function body ( not in a branch) then we know that this function would assert if called at runtime. And therefore no correct code can be calling it. which also means we can forgo having code-gen or optimization for the function body. and reduce the count of names which has to get mangled. They only downside to this, is that giving assert(__ctfe) the special meaning to skip codegen might be confusing to some people .... then again you wouldn't use assert(__ctfe) unless you expect that function to not be available at run-time What do you guys think?For many years I wanted a feature that could indicate a function is only used at compile time. BTW, this is a breaking change. Consider this code: import core.exception; void foo() { assert(__ctfe); } void main() system { try foo(); catch (AssertError) {} } -- /Jacob Carlborg
Apr 07 2020
On Tuesday, 7 April 2020 at 17:52:44 UTC, Jacob Carlborg wrote:BTW, this is a breaking change. Consider this code: import core.exception; void foo() { assert(__ctfe); } void main() system { try foo(); catch (AssertError) {} }Catching an AssertError thrown by an assert statement is officially undefined behavior: https://dlang.org/spec/expression.html#assert_expressions
Apr 07 2020
On 2020-04-07 21:33, tsbockman wrote:Catching an AssertError thrown by an assert statement is officially undefined behavior: https://dlang.org/spec/expression.html#assert_expressionsOk, let me tweak the example a bit: void foo() { assert(__ctfe); } unittest system { try foo(); catch (AssertError) {} } Then if you read the third item in the list: "AssertExpression has different semantics if it is in a unittest or in contract." Then you read the unittest spec [1], the third item, the second sentence: "Unlike AssertExpressions used elsewhere, the assert is not assumed to hold, and upon assert failure the program is still in a defined state." Now it's not undefined anymore. [1] https://dlang.org/spec/unittest.html -- /Jacob Carlborg
Apr 08 2020
On Tuesday, 7 April 2020 at 17:52:44 UTC, Jacob Carlborg wrote:void foo() { assert(__ctfe); } void main() system { try foo(); catch (AssertError) {} }firstly Does anybody actually do this? secondly your program either complies with no change (i.e. the assert never fired), or you get a message telling you that ctfe-only functions can't be called at runtime.
Apr 07 2020
On 2020-04-07 22:43, Stefan Koch wrote:On Tuesday, 7 April 2020 at 17:52:44 UTC, Jacob Carlborg wrote:Ok, let me tweak the example a bit: void foo() { assert(__ctfe); } unittest { foo(); } druntime catches _all_ exceptions: https://github.com/dlang/druntime/blob/46867186035fdf5ec2596efbb770627518ff0919/src/core/runtime.d#L617 Regardless if anyone does it or not, it's still a breaking change. Then we can of course argue the impact of the breaking change, how much code will actually break. -- /Jacob Carlborgvoid foo() { assert(__ctfe); } void main() system { try foo(); catch (AssertError) {} }firstly Does anybody actually do this?
Apr 08 2020
On 4/8/20 2:53 PM, Jacob Carlborg wrote:On 2020-04-07 22:43, Stefan Koch wrote:I think it's a breaking change, just like flagging any obvious error case as a non-compilable error is a breaking change for code that wasn't aware of the problem. I'm sure there was lots of code that did something equivalent to this before it was disallowed: ref int foo() { int x; return x; } That doesn't mean we shouldn't do it. -SteveOn Tuesday, 7 April 2020 at 17:52:44 UTC, Jacob Carlborg wrote:Ok, let me tweak the example a bit: void foo() { assert(__ctfe); } unittest { foo(); } druntime catches _all_ exceptions: https://github.com/dlang/druntime/blob/46867186035fdf5ec2596efbb770627518ff0919/src core/runtime.d#L617 Regardless if anyone does it or not, it's still a breaking change. Then we can of course argue the impact of the breaking change, how much code will actually break.void foo() { assert(__ctfe); } void main() system { try foo(); catch (AssertError) {} }firstly Does anybody actually do this?
Apr 08 2020
On 4/8/20 2:53 PM, Jacob Carlborg wrote:Regardless if anyone does it or not, it's still a breaking change. Then we can of course argue the impact of the breaking change, how much code will actually break.another interesting case: void foo() { assert(__ctfe); } void main(string[] args) { if(args.length == 0) foo(0); } Arguably, the call will never happen. But it won't compile now. As I said a minute ago, this is a breaking change, and it's one we should make. -Steve
Apr 08 2020
On 4/8/20 3:04 PM, Steven Schveighoffer wrote:foo(0);Ugh, that should have been foo();, forgot to edit that. -Steve
Apr 08 2020
On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:Hi Guys, [...] What do you guys think? Cheers, StefanOther and new thought. This will have a positive impact on coverage maybe ? I opened this a while ago: https://issues.dlang.org/show_bug.cgi?id=15590 (0 coverage should be ignored in __ctfe branches) The problem would be partially solved when splitting the function in two versions.
Apr 09 2020
On Thursday, 9 April 2020 at 10:14:21 UTC, Basile B. wrote:On Sunday, 5 April 2020 at 12:11:23 UTC, Stefan Koch wrote:well ... splitting the function in two versions comes with the oblivious overhead of having to run semantic two times. As well as having to maintain that in a multi-pass compilation model which we have to avoid having headers and that gives use the power to declare anywhere.Hi Guys, [...] What do you guys think? Cheers, StefanOther and new thought. This will have a positive impact on coverage maybe ? I opened this a while ago: https://issues.dlang.org/show_bug.cgi?id=15590 (0 coverage should be ignored in __ctfe branches) The problem would be partially solved when splitting the function in two versions.
Apr 09 2020