www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Failure due to memcpy being called at compile time

reply JG <someone somewhere.com> writes:
Hi,

I reduced my code to the following.  Could anyone help me to 
discover why the line marked with //THIS LINE

causes memcpy to be called, and how can I avoid this?


```d
import std;

struct ParseError { string msg; }

alias ParseErrorOr(T) = SumType!(ParseError,T);
auto parseErrorOr(T)(T x) { return ParseErrorOr!T(x); }

auto parserOr(I,fs...)(I i) {
   alias RetType = typeof(fs[0](I.init));
   auto cur = RetType(ParseError.init);
   foreach(f;fs) {
     if(cur.match!((ParseError e)=>false,_=>true)) { return cur; }
     cur = f(i); //THIS LINE
   }
   return cur;
}

auto parseNothing(I)(I i) {
     return parseErrorOr(tuple(i[0..0],i));
}

void main()
{
     enum a = 
parserOr!(string,parseNothing!string,parseNothing!string)("hello");
}
```
Jun 13 2022
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 6/13/22 3:48 PM, JG wrote:
 Hi,
 
 I reduced my code to the following.  Could anyone help me to discover 
 why the line marked with //THIS LINE
 
 causes memcpy to be called, and how can I avoid this?
 
 
 ```d
 import std;
 
 struct ParseError { string msg; }
 
 alias ParseErrorOr(T) = SumType!(ParseError,T);
 auto parseErrorOr(T)(T x) { return ParseErrorOr!T(x); }
 
 auto parserOr(I,fs...)(I i) {
    alias RetType = typeof(fs[0](I.init));
    auto cur = RetType(ParseError.init);
    foreach(f;fs) {
      if(cur.match!((ParseError e)=>false,_=>true)) { return cur; }
      cur = f(i); //THIS LINE
    }
    return cur;
 }
 
 auto parseNothing(I)(I i) {
      return parseErrorOr(tuple(i[0..0],i));
 }
 
 void main()
 {
      enum a = 
 parserOr!(string,parseNothing!string,parseNothing!string)("hello");
 }
 ```
 
 
 
Happens in `moveEmplaceImpl` in `core.lifetime`. Somebody is calling that. https://github.com/dlang/druntime/blob/v2.099.1/src/core/lifetime.d#L2192 No stack trace though, that would actually be nice to have in the CTFE interpreter. I imagine if you solved that call, you would get out to a place where it tries to cast to the actual type and fail there instead. -Steve
Jun 13 2022
parent reply JG <someone somewhere.com> writes:
On Monday, 13 June 2022 at 19:59:16 UTC, Steven Schveighoffer 
wrote:
 On 6/13/22 3:48 PM, JG wrote:
 Hi,
 
 I reduced my code to the following.  Could anyone help me to 
 discover why the line marked with //THIS LINE
 
 causes memcpy to be called, and how can I avoid this?
 
 
 ```d
 import std;
 
 struct ParseError { string msg; }
 
 alias ParseErrorOr(T) = SumType!(ParseError,T);
 auto parseErrorOr(T)(T x) { return ParseErrorOr!T(x); }
 
 auto parserOr(I,fs...)(I i) {
    alias RetType = typeof(fs[0](I.init));
    auto cur = RetType(ParseError.init);
    foreach(f;fs) {
      if(cur.match!((ParseError e)=>false,_=>true)) { return 
 cur; }
      cur = f(i); //THIS LINE
    }
    return cur;
 }
 
 auto parseNothing(I)(I i) {
      return parseErrorOr(tuple(i[0..0],i));
 }
 
 void main()
 {
      enum a = 
 parserOr!(string,parseNothing!string,parseNothing!string)("hello");
 }
 ```
 
 
 
Happens in `moveEmplaceImpl` in `core.lifetime`. Somebody is calling that. https://github.com/dlang/druntime/blob/v2.099.1/src/core/lifetime.d#L2192 No stack trace though, that would actually be nice to have in the CTFE interpreter. I imagine if you solved that call, you would get out to a place where it tries to cast to the actual type and fail there instead. -Steve
Thanks. It seems to be something to do with the variadic template since this works: ```d import std; struct ParseError { string msg; } alias ParseErrorOr(T) = SumType!(ParseError,T); auto parseErrorOr(T)(T x) { return ParseErrorOr!T(x); } auto parserOr(I,alias f, alias g)(I i) { auto cur = f(i); if(cur.match!((ParseError e)=>false,_=>true)) { return cur; } return g(i); } auto parseNothing(I)(I i) { return parseErrorOr(tuple(i[0..0],i)); } void main() { enum a = parserOr!(string,parseNothing!string,parseNothing!string)("hello"); } ```
Jun 13 2022
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 6/13/22 4:09 PM, JG wrote:
 Thanks. It seems to be something to do with the variadic template since 
 this
 works:
 
 ```d
 import std;
 
 struct ParseError { string msg; }
 
 alias ParseErrorOr(T) = SumType!(ParseError,T);
 auto parseErrorOr(T)(T x) { return ParseErrorOr!T(x); }
 
 auto parserOr(I,alias f, alias g)(I i) {
    auto cur = f(i);
    if(cur.match!((ParseError e)=>false,_=>true)) { return cur; }
    return g(i);
 }
 
 auto parseNothing(I)(I i) {
      return parseErrorOr(tuple(i[0..0],i));
 }
 
 void main()
 {
      enum a = 
 parserOr!(string,parseNothing!string,parseNothing!string)("hello");
 }
 ```
Given that it's inside `moveEmplace`, I'd suspect something deep in `SumType`. -Steve
Jun 13 2022
parent JG <someone somewhere.com> writes:
On Monday, 13 June 2022 at 20:25:00 UTC, Steven Schveighoffer 
wrote:
 On 6/13/22 4:09 PM, JG wrote:
 Thanks. It seems to be something to do with the variadic 
 template since this
 works:
 
 ```d
 import std;
 
 struct ParseError { string msg; }
 
 alias ParseErrorOr(T) = SumType!(ParseError,T);
 auto parseErrorOr(T)(T x) { return ParseErrorOr!T(x); }
 
 auto parserOr(I,alias f, alias g)(I i) {
    auto cur = f(i);
    if(cur.match!((ParseError e)=>false,_=>true)) { return cur; 
 }
    return g(i);
 }
 
 auto parseNothing(I)(I i) {
      return parseErrorOr(tuple(i[0..0],i));
 }
 
 void main()
 {
      enum a = 
 parserOr!(string,parseNothing!string,parseNothing!string)("hello");
 }
 ```
Given that it's inside `moveEmplace`, I'd suspect something deep in `SumType`. -Steve
Really strange. I can also work around it like this: ```d auto parserOr(I,fs...)(I i) if(fs.length>=2) { auto cur = fs[0](i); if(cur.match!((ParseError e)=>false,_=>true)) { return cur; } static if(fs.length==2) { return fs[1](i); } else { return parserOr!(I,fs[1..$])(i); } } ```
Jun 13 2022
prev sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Monday, 13 June 2022 at 19:48:06 UTC, JG wrote:
 Hi,

 I reduced my code to the following.  Could anyone help me to 
 discover why the line marked with //THIS LINE

 causes memcpy to be called, and how can I avoid this?
Reduced further: ```d import std.sumtype; struct Tuple { void opAssign(Tuple rhs) {} } alias ParseErrorOr = SumType!Tuple; auto parserOr() { ParseErrorOr cur; cur = ParseErrorOr(Tuple()); return cur; } void main() { enum a = parserOr(); } ``` The call to `move` is coming from `SumType.opAssign`: https://github.com/dlang/phobos/blob/v2.100.0/std/sumtype.d#L681 I've filed a bugzilla issue for this here: https://issues.dlang.org/show_bug.cgi?id=23182
Jun 13 2022
parent reply JG <someone somewhere.com> writes:
On Monday, 13 June 2022 at 21:45:39 UTC, Paul Backus wrote:
 On Monday, 13 June 2022 at 19:48:06 UTC, JG wrote:
 Hi,

 I reduced my code to the following.  Could anyone help me to 
 discover why the line marked with //THIS LINE

 causes memcpy to be called, and how can I avoid this?
Reduced further: ```d import std.sumtype; struct Tuple { void opAssign(Tuple rhs) {} } alias ParseErrorOr = SumType!Tuple; auto parserOr() { ParseErrorOr cur; cur = ParseErrorOr(Tuple()); return cur; } void main() { enum a = parserOr(); } ``` The call to `move` is coming from `SumType.opAssign`: https://github.com/dlang/phobos/blob/v2.100.0/std/sumtype.d#L681 I've filed a bugzilla issue for this here: https://issues.dlang.org/show_bug.cgi?id=23182
Thanks, for doing this.
Jun 13 2022
parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 14 June 2022 at 05:35:46 UTC, JG wrote:
 On Monday, 13 June 2022 at 21:45:39 UTC, Paul Backus wrote:
 The call to `move` is coming from `SumType.opAssign`:

 https://github.com/dlang/phobos/blob/v2.100.0/std/sumtype.d#L681

 I've filed a bugzilla issue for this here:

 https://issues.dlang.org/show_bug.cgi?id=23182
Thanks, for doing this.
Update: a new release of [the `sumtype` package on code.dlang.org][1] is available that includes the fix for this bug. `std.sumtype` will be fixed in the next Phobos release, 2.100.1. [1]: https://code.dlang.org/packages/sumtype
Jun 20 2022
parent reply JG <someone simewhere.com> writes:
On Tuesday, 21 June 2022 at 01:39:43 UTC, Paul Backus wrote:
 On Tuesday, 14 June 2022 at 05:35:46 UTC, JG wrote:
 On Monday, 13 June 2022 at 21:45:39 UTC, Paul Backus wrote:
 The call to `move` is coming from `SumType.opAssign`:

 https://github.com/dlang/phobos/blob/v2.100.0/std/sumtype.d#L681

 I've filed a bugzilla issue for this here:

 https://issues.dlang.org/show_bug.cgi?id=23182
Thanks, for doing this.
Update: a new release of [the `sumtype` package on code.dlang.org][1] is available that includes the fix for this bug. `std.sumtype` will be fixed in the next Phobos release, 2.100.1. [1]: https://code.dlang.org/packages/sumtype
That is great. Is this a work around the CFE bug?
Jun 20 2022
parent Paul Backus <snarwin gmail.com> writes:
On Tuesday, 21 June 2022 at 04:30:25 UTC, JG wrote:
 On Tuesday, 21 June 2022 at 01:39:43 UTC, Paul Backus wrote:
 Update: a new release of [the `sumtype` package on 
 code.dlang.org][1] is available that includes the fix for this 
 bug.

 `std.sumtype` will be fixed in the next Phobos release, 
 2.100.1.

 [1]: https://code.dlang.org/packages/sumtype
That is great. Is this a work around the CFE bug?
Yes, it's a workaround to avoid calling memcpy in CTFE.
Jun 21 2022