February 26, 2020
https://issues.dlang.org/show_bug.cgi?id=19268

--- Comment #6 from Adam D. Ruppe <destructionator@gmail.com> ---
I think my proposal would be that *specifically* the `if(__ctfe)` construct overrides the betterC checks, since that can be easily factored out.

Just like how we can write

---
int* do_something() {
   if(__ctfe) {
       return new int;
   } else {
       return cast(int*) malloc(int.sizeof);
   }
}
enum e = *do_something();
---

today (which works in real D, including without linking druntime btw), which bypasses the normal "malloc cannot be evaluated at compile time), we could conceivably use it in the other direction to allow something in a CT context that isn't allowed in a RT context.

I'm not sure how to write that in spec language... it might be able to just say specifically that betterC's restrictions do not apply inside that specific ast node and like specifically hack the hack that is betterC.


I think that would be fine with `__traits(compiles)` as well. The `if(__ctfe)` switch keeps everything compiling the same way - it is specifically a runtime branch in terms of formal semantics. So the compiles thing passes because that if branch is encapsulated still.

--
February 26, 2020
https://issues.dlang.org/show_bug.cgi?id=19268

--- Comment #7 from Steven Schveighoffer <schveiguy@yahoo.com> ---
(In reply to ZombineDev from comment #5)
> I guess the trickiest problem to solve is what to do about is(typeof({ code; })) and __traits(compiles, { code; }). Allowing those constructs to yield true while containing non-betterc code would lead to logical contradictions. Disallowing betterc code in such speculative contexts, while allowing it in CTFE context would be strange.

This is a good point. CTFE is hard because it still needs to compile, even though in this case you won't actually run that code.

I would say that functions that are not going into the object symbol table can be compiled and run for CTFE only. If you do try to refer to that symbol during runtime, then throw the error.

I don't know how hard this is to do, but it seems possible.

possibly another answer is to revert the binding to druntime idup in betterC mode (obviously this worked before).

--
February 26, 2020
https://issues.dlang.org/show_bug.cgi?id=19268

--- Comment #8 from Adam D. Ruppe <destructionator@gmail.com> ---
My view is that the code compiles just fine. Just without druntime linked in or generated typeinfo, or whatever it depends on at run time, it will not link.

The -betterC switch tries to detect these these would-be linker errors and report them ahead of time, in the compile step, for more consistent and user-friendly errors.

Since an `if(__ctfe)` branch (or `mixin` or `pragma(msg)` or any other
unambiguously* compile-time only area) is never actually involved in code
generation, that linker error will never actually happen... and the compiler
*should* know that and not cause the ahead-of-time compile error eiter.

* __traits(compiles) (and is(typeof())) is a grey area. Technically it isn't
generating code at all and thus should not generate a linker error, and thus
not generate the betterC error.... but given how it is used in practice I think
it should assume the stuff inside WILL be used for codegen and thus return
false in these cases.

But when in doubt, I say `-betterC` should aim to give the same end result as `-defaultlib=` just with compile errors instead of linker undefined symbol errors.

--
February 26, 2020
https://issues.dlang.org/show_bug.cgi?id=19268

--- Comment #9 from Steven Schveighoffer <schveiguy@yahoo.com> ---
(In reply to Adam D. Ruppe from comment #8)
> My view is that the code compiles just fine. Just without druntime linked in or generated typeinfo, or whatever it depends on at run time, it will not link.
> 
> The -betterC switch tries to detect these these would-be linker errors and report them ahead of time, in the compile step, for more consistent and user-friendly errors.

Right, this is my view too.

> Since an `if(__ctfe)` branch (or `mixin` or `pragma(msg)` or any other
> unambiguously* compile-time only area) is never actually involved in code
> generation, that linker error will never actually happen... and the compiler
> *should* know that and not cause the ahead-of-time compile error eiter.

Except this is not the problem. The CTFE part DOES compile. It's the part that's outside that doesn't (in fact typeid(x) does not compile during CTFE). So how do you "compile" that, and only allow it to run at compile time? That's why this is hard.

Any solution for detecting druntime usage is not going to be perfect. For example, this doesn't have compile errors but linker errors (with -betterC):

import core.thread;
import core.time;

extern(C) void main()
{
    Thread.sleep(1.seconds);
}

And of course, __traits(compiles) is going to say YES to this. So it is indeed
a gray area.

--
February 26, 2020
https://issues.dlang.org/show_bug.cgi?id=19268

--- Comment #10 from Steven Schveighoffer <schveiguy@yahoo.com> ---
Ooooh, I just had an idea. Consider the template that is causing issues _dup. What if we did this:

version(D_BetterC) extern(C) void _dup_UNAVAILABLE_IN_BETTERC();

private U[] _dup(T, U)(T[] a) // pure nothrow depends on postblit
{
    if (__ctfe)
    { /* ctfe code */ }

    version(D_BetterC) {
        _dup_UNAVAILABLE_IN_BETTERC();
        return U[].init;
    }
    else:

    // normal implementation that uses typeid
}

This defers the error to the linker, but with the message identifying which function is causing the problem. We can probably make an easy mixin to do this wherever needed.

In essence this is a compiler error, with a "funky" but albeit legible message.

But this does change idup to return true for __traits(compiles). Is that a
problem? I'd say no. Use the version(D_BetterC) instead of __traits(compiles).

Aaand, it doesn't work. Using a template at compile time for some reason makes the compiler want to link in the symbol. I think there is no way to make this work unless the compiler is smarter about what it used at compile time vs. runtime.

--
February 26, 2020
https://issues.dlang.org/show_bug.cgi?id=19268

--- Comment #11 from Steven Schveighoffer <schveiguy@yahoo.com> ---
(In reply to ZombineDev from comment #5)
> I guess the trickiest problem to solve is what to do about is(typeof({ code; })) and __traits(compiles, { code; }). Allowing those constructs to yield true while containing non-betterc code would lead to logical contradictions. Disallowing betterc code in such speculative contexts, while allowing it in CTFE context would be strange.

When trying to test stuff surrounding this, I'll note that a betterC error seems to kill the compilation when used inside __traits(compiles).

This prints nothing and produces no binary:

extern(C) void main()
{
   int[] arr;
   pragma(msg, __traits(compiles, arr.idup));
}

--
February 26, 2020
https://issues.dlang.org/show_bug.cgi?id=19268

--- Comment #12 from Adam D. Ruppe <destructionator@gmail.com> ---
(In reply to Steven Schveighoffer from comment #9)
> Except this is not the problem. The CTFE part DOES compile.

eeeeh, it is the problem that brought me to this bug.

private string makefoo() {
        if(__ctfe) {
                string a = "b";
                a ~= "c\0";
                return a;
        }
        assert(0);
}

enum foo = makefoo();

extern(C) int main() {
        import core.stdc.stdio;
        printf("%s", foo.ptr);
        return 0;
}

Here that private function is obviously intended to be CTFE only - the `private` and `if(__ctfe)` make that extremely clear to a human reader, but the compiler doesn't get the hint.

We could also do a like `pragma(ct_only)` maybe just I was hoping this pattern
would work since it is in the existing language. But nope :(

--
October 18, 2021
https://issues.dlang.org/show_bug.cgi?id=19268

Paul Backus <snarwin+bugzilla@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |maxhaton@gmail.com

--- Comment #13 from Paul Backus <snarwin+bugzilla@gmail.com> ---
*** Issue 20086 has been marked as a duplicate of this issue. ***

--
January 15, 2023
https://issues.dlang.org/show_bug.cgi?id=19268

Walter Bright <bugzilla@digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
            Summary|BetterC turns off DRuntime  |BetterC turns off .dup for
                   |for CTFE                    |CTFE

--
January 15, 2023
https://issues.dlang.org/show_bug.cgi?id=19268

Dlang Bot <dlang-bot@dlang.rocks> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |pull

--- Comment #14 from Dlang Bot <dlang-bot@dlang.rocks> ---
@WalterBright created dlang/dmd pull request #14819 "fix Issue 19268 - BetterC turns off .dup for CTFE" fixing this issue:

- fix Issue 19268 - BetterC turns off .dup for CTFE

https://github.com/dlang/dmd/pull/14819

--