Thread overview
[Issue 23643] [betterC] Better Error Message For CTFE GC Usage
Jan 20
RazvanN
Jan 24
RazvanN
January 20
https://issues.dlang.org/show_bug.cgi?id=23643

RazvanN <razvan.nitu1305@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |razvan.nitu1305@gmail.com

--- Comment #1 from RazvanN <razvan.nitu1305@gmail.com> ---
(In reply to Jack Stouffer from comment #0)
> Consider the following real code example,
> 
> 
>     char[] unsignedToTempString(uint radix = 10)(ulong value, return scope
> char[] buf) @safe
>         if (radix >= 2 && radix <= 16)
>     {
>         size_t i = buf.length;
>         do
>         {
>             uint x = void;
>             if (value < radix)
>             {
>                 x = cast(uint)value;
>                 value = 0;
>             }
>             else
>             {
>                 x = cast(uint)(value % radix);
>                 value /= radix;
>             }
>             buf[--i] = cast(char)((radix <= 10 || x < 10) ? x + '0' : x - 10
> + 'a');
>         } while (value);
>         return buf[i .. $];
>     }
> 
>     char[] myToString(ulong n)
>     {
>         char[20] buf;
>         auto s = unsignedToTempString(n, buf);
>         return s ~ (n > uint.max ? "UL" : "U");
>     }
> 
>     enum a = myToString(5);
> 
> This gives the following error
> 
>     Error: array concatenation of expression `cast(const(char)[])s ~ (n >
> 4294967295LU ? "UL" : "U")` requires the GC which is not available with
> -betterC
> 
> The problem here is that DMD is trying to include the function myToString into the object file even though it's only being used during CTFE. The fix for this code is to make myToString a template. But the chance that a user is going to know that is very low.
> 
> The compiler knows that it encountered this function during the CTFE run. So it should give a helpful error message, something like.
> 
>     Error: array concatenation of expression `cast(const(char)[])s ~ (n >
> 4294967295LU ? "UL" : "U")` requires the GC which is not available with
> -betterC
> 
>     This GC allocation was encountered during CTFE. If this function is
> supposed to be a CTFE only function then this error can be fixed by making
> the function a template.
> 
> Simple, easy to understand, and very helpful.

I'm sorry but I don't agree that this is a bug. The compiler cannot know if you want the function to be ctfe only or if it is going to be called from a different object file. Since the function is not a template, the compiler assumes that you want the object code for it and therefore nags you about the fact that you are doing illegal operations for betterC. If you want it to be ctfe only, just template it.

What you are asking for is for the compiler to keep track of whether a function is called from ctfe or runtime contexts and if it is called only from ctfe to decide to either not output the object code or give some indication on how to fix this. But what if the person implementing myToString wants to call it from a different file and needs to have the object file working with betterC? Than the error is misleading.

The error is correct: you are using druntime in a function that is betterC.

--
January 23
https://issues.dlang.org/show_bug.cgi?id=23643

--- Comment #2 from Jack Stouffer <jack@jackstouffer.com> ---
(In reply to RazvanN from comment #1)
> Since the function is not a template, the compiler
> assumes that you want the object code for it and therefore nags you about
> the fact that you are doing illegal operations for betterC. If you want it
> to be ctfe only, just template it.

And we're just going to assume that everyone who tries to use betterC is going to know this? Highly unlikely. I've been working with D for eight years; the thought of templating the function never occurred to me. I just assumed there was a bug in the compiler since I was only using the function in CTFE.

> What you are asking for is for the compiler to keep track of whether a function is called from ctfe or runtime contexts and if it is called only from ctfe to decide to either not output the object code or give some indication on how to fix this. But what if the person implementing myToString wants to call it from a different file and needs to have the object file working with betterC? Than the error is misleading.

Let me give you another example of something very similar that DMD already does:

void main() {
    writeln("Hello!");
}

Error: `writeln` is not defined, perhaps `import std.stdio;` is needed?

Simple to read and gives the user the most likely solution to their problem. A great error message! But, it's also possible that the user has their own writeln function and they forgot to import that and not std.stdio.

A contrived example? No, this literally happened to me yesterday since I DO have my own writeln. The fact the compiler gave me the wrong solution to my problem did not bother me and was not an issue.

There is absolutely no downside to being a little more verbose in the error messages. Obviously you can go too far towards the other end of the verbosity spectrum. But what I'm asking here is for DMD to nudge the user along in most likely the correct direction with a problem that's probably confusing.

--
January 23
https://issues.dlang.org/show_bug.cgi?id=23643

Jack Stouffer <jack@jackstouffer.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |betterC, diagnostic

--
January 24
https://issues.dlang.org/show_bug.cgi?id=23643

--- Comment #3 from RazvanN <razvan.nitu1305@gmail.com> ---
(In reply to Jack Stouffer from comment #2)
> (In reply to RazvanN from comment #1)
> > Since the function is not a template, the compiler
> > assumes that you want the object code for it and therefore nags you about
> > the fact that you are doing illegal operations for betterC. If you want it
> > to be ctfe only, just template it.
> 
> And we're just going to assume that everyone who tries to use betterC is going to know this? Highly unlikely. I've been working with D for eight years; the thought of templating the function never occurred to me. I just assumed there was a bug in the compiler since I was only using the function in CTFE.
> 
> > What you are asking for is for the compiler to keep track of whether a function is called from ctfe or runtime contexts and if it is called only from ctfe to decide to either not output the object code or give some indication on how to fix this. But what if the person implementing myToString wants to call it from a different file and needs to have the object file working with betterC? Than the error is misleading.
> 
> Let me give you another example of something very similar that DMD already does:
> 
> void main() {
>     writeln("Hello!");
> }
> 
> Error: `writeln` is not defined, perhaps `import std.stdio;` is needed?
> 
> Simple to read and gives the user the most likely solution to their problem. A great error message! But, it's also possible that the user has their own writeln function and they forgot to import that and not std.stdio.
> 
> A contrived example? No, this literally happened to me yesterday since I DO have my own writeln. The fact the compiler gave me the wrong solution to my problem did not bother me and was not an issue.
> 
> There is absolutely no downside to being a little more verbose in the error messages. Obviously you can go too far towards the other end of the verbosity spectrum. But what I'm asking here is for DMD to nudge the user along in most likely the correct direction with a problem that's probably confusing.

I understand what you are saying however, the frequency of forgetting to import std.stdio is much larger than that of people expecting their normal functions not outputting object code when called only from ctfe.

The main problem here is not verbosity, rather adding extra complexity for a measly error message. Also, I am not convinced that your expectation represents what other users expect. If you define a normal function, it doesn't matter from were you call it, its object code is going to be generated. That is true for non-betterC code and I don't see why betterC code would change that. Also, what happens with code that is correct betterC but is used in ctfe contexts only? Are we going to omit object code for it also? What happens when the user wants to link the file containing myToString with another object file? Are we just going to let the user face the linker issues? That is more problematic than the current situation.

--