www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - template ctor overload Segmentation fault

reply vit <vit vit.vit> writes:
Hello, why does this code fail to compile?

```d
struct Foo(T){
     this(Rhs, this This)(scope Rhs rhs){
     }

     this(ref scope typeof(this) rhs){
     }
}


struct Bar{
	Foo!int foo;
}

void main(){
}
```

error: Segmentation fault (core dumped)
Dec 12 2021
next sibling parent reply Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote:
 Hello, why does this code fail to compile?

 ```d
 struct Foo(T){
     this(Rhs, this This)(scope Rhs rhs){
     }

     this(ref scope typeof(this) rhs){
     }
 }


 struct Bar{
 	Foo!int foo;
 }

 void main(){
 }
 ```

 error: Segmentation fault (core dumped)
What are you trying to accomplish?
Dec 12 2021
parent reply vit <vit vit.vit> writes:
On Sunday, 12 December 2021 at 18:32:28 UTC, Imperatorn wrote:
 On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote:
 Hello, why does this code fail to compile?

 ```d
 struct Foo(T){
     this(Rhs, this This)(scope Rhs rhs){
     }

     this(ref scope typeof(this) rhs){
     }
 }


 struct Bar{
 	Foo!int foo;
 }

 void main(){
 }
 ```

 error: Segmentation fault (core dumped)
What are you trying to accomplish?
Something like this: ```d import std.traits : CopyConstness; struct UniquePtr(T){ alias Type = T; this(Rhs, this This)(scope Rhs rhs) if(is(CopyConstness!(Rhs, Rhs.Type*) : CopyConstness!(This, This.Type*))){ //... } //one of copy ctors: this(ref scope typeof(this) rhs){ //... } static UniquePtr make(Args...)(Args args){ return UniquePtr.init; } } void main(){ const UniquePtr!(int) cui = UniquePtr!(const int).make(1); const UniquePtr!(const int) cuci = UniquePtr!(const int).make(1); UniquePtr!(const int) uci = UniquePtr!(int).make(1); UniquePtr!(int) ui = UniquePtr!(int).make(1); const UniquePtr!(int) xcui = UniquePtr!(immutable int).make(1); const UniquePtr!(const int) xcuci = UniquePtr!(immutable int).make(1); } ``` This work but UniquePtr canno't be inside struct because Segmentation fault.
Dec 12 2021
parent Tejas <notrealemail gmail.com> writes:
On Sunday, 12 December 2021 at 19:17:53 UTC, vit wrote:
 On Sunday, 12 December 2021 at 18:32:28 UTC, Imperatorn wrote:
 On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote:
 Hello, why does this code fail to compile?

 ```d
 struct Foo(T){
     this(Rhs, this This)(scope Rhs rhs){
     }

     this(ref scope typeof(this) rhs){
     }
 }


 struct Bar{
 	Foo!int foo;
 }

 void main(){
 }
 ```

 error: Segmentation fault (core dumped)
What are you trying to accomplish?
Something like this: ```d import std.traits : CopyConstness; struct UniquePtr(T){ alias Type = T; this(Rhs, this This)(scope Rhs rhs) if(is(CopyConstness!(Rhs, Rhs.Type*) : CopyConstness!(This, This.Type*))){ //... } //one of copy ctors: this(ref scope typeof(this) rhs){ //... } static UniquePtr make(Args...)(Args args){ return UniquePtr.init; } } void main(){ const UniquePtr!(int) cui = UniquePtr!(const int).make(1); const UniquePtr!(const int) cuci = UniquePtr!(const int).make(1); UniquePtr!(const int) uci = UniquePtr!(int).make(1); UniquePtr!(int) ui = UniquePtr!(int).make(1); const UniquePtr!(int) xcui = UniquePtr!(immutable int).make(1); const UniquePtr!(const int) xcuci = UniquePtr!(immutable int).make(1); } ``` This work but UniquePtr canno't be inside struct because Segmentation fault.
This made your previous snippet work: ```d struct Foo(T){ this(Rhs, this This)(scope Rhs rhs){ } this(scope Foo!(T)* rhs){ } } struct Bar{ Foo!int foo; } void main(){ import std.stdio:writeln; Bar bar = Bar(); auto BAR = new Bar(); writeln(bar, "\t", BAR, "\t", *BAR); } ``` Definitely something funky going on behind the scenes. I also think you should post a bug, like the above user said.
Dec 13 2021
prev sibling next sibling parent user1234 <user1234 12.de> writes:
On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote:
 Hello, why does this code fail to compile?

 ```d
 struct Foo(T){
     this(Rhs, this This)(scope Rhs rhs){
     }

     this(ref scope typeof(this) rhs){
     }
 }


 struct Bar{
 	Foo!int foo;
 }

 void main(){
 }
 ```

 error: Segmentation fault (core dumped)
Firstly, report the crash with the keyword "ice". Then, there might be something not allowed (in some situations the compiler cant decide which ctor to use) but you cant see it for now.
Dec 13 2021
prev sibling next sibling parent reply RazvanN <razvan.nitu1305 gmail.com> writes:
On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote:
 Hello, why does this code fail to compile?

 ```d
 struct Foo(T){
     this(Rhs, this This)(scope Rhs rhs){
     }

     this(ref scope typeof(this) rhs){
     }
 }


 struct Bar{
 	Foo!int foo;
 }

 void main(){
 }
 ```

 error: Segmentation fault (core dumped)
The problem is that the compiler will try to generate an inout copy constructor for Bar that looks roughly like this: ``` this(ref scope inout(Bar) p) inout { this.foo = p; } ``` The idea behind this lowering is to try and call the copy constructor for Foo object if possible. One issue here is that copy constructors have the same symbol name as constructors (__ctor), so `this.foo = p` gets lowered to `foo.__ctor(p)`. Since both the instance and the parameter are inout, the copy constructor of Foo cannot be called, so the templated constructor is called. After generating the template instance of the constructor, you end up with `this(scope inout(Foo)) inout` ; that is basically an rvalue constructor. This is not valid code; if you write: ``` struct Foo(T){ //this(Rhs, this This)(scope Rhs rhs){} this(scope inout(Foo!int) rhs) inout {} this(ref scope typeof(this) rhs){ } } ``` You will get an error stating that you cannot define both an rvalue constructor and a copy constructor. However, since the constructor is templated it is impossible for the compiler to issue this error before actually instantiating the constructor. I see 2 possible fixes for this: (1) either we rename the copy constructor symbol to __cpCtor so that it does not clash with the normal constructor overload set or (2) when a templated constructor is instantiated, we can check whether it is an rvalue constructor and issue an error if a copy constructor exists. When I implemented the copy constructor I thought that it would better to have the copy constructor on a different overload set than the normal constructors, however, Walter insisted that they have the same name. So, I guess (2) is the way to go. Cheers, RazvanN
Dec 14 2021
parent reply Tejas <notrealemail gmail.com> writes:
On Tuesday, 14 December 2021 at 12:04:36 UTC, RazvanN wrote:
 On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote:
 [...]
The problem is that the compiler will try to generate an inout copy constructor for Bar that looks roughly like this: ``` this(ref scope inout(Bar) p) inout { this.foo = p; } ``` The idea behind this lowering is to try and call the copy constructor for Foo object if possible. One issue here is that copy constructors have the same symbol name as constructors (__ctor), so `this.foo = p` gets lowered to `foo.__ctor(p)`. Since both the instance and the parameter are inout, the copy constructor of Foo cannot be called, so the templated constructor is called. After generating the template instance of the constructor, you end up with `this(scope inout(Foo)) inout` ; that is basically an rvalue constructor. This is not valid code; if you write: ``` struct Foo(T){ //this(Rhs, this This)(scope Rhs rhs){} this(scope inout(Foo!int) rhs) inout {} this(ref scope typeof(this) rhs){ } } ``` You will get an error stating that you cannot define both an rvalue constructor and a copy constructor. However, since the constructor is templated it is impossible for the compiler to issue this error before actually instantiating the constructor. I see 2 possible fixes for this: (1) either we rename the copy constructor symbol to __cpCtor so that it does not clash with the normal constructor overload set or (2) when a templated constructor is instantiated, we can check whether it is an rvalue constructor and issue an error if a copy constructor exists. When I implemented the copy constructor I thought that it would better to have the copy constructor on a different overload set than the normal constructors, however, Walter insisted that they have the same name. So, I guess (2) is the way to go. Cheers, RazvanN
Then why did my modification work? ```d struct Foo(T){ this(Rhs, this This)(scope Rhs rhs){ } this(scope Foo!(T)* rhs){ //replaced typeof(this) with Foo!T and ref with pointer. Code still works if I retain typeof(this) } } struct Bar{ Foo!int foo; } void main(){ import std.stdio:writeln; Bar bar = Bar(); auto BAR = new Bar(); writeln(bar, "\t", BAR, "\t", *BAR); } ``` Did my modifications ensure that this is not treated as a copy constructor?
Dec 14 2021
parent RazvanN <razvan.nitu1305 gmail.com> writes:
On Tuesday, 14 December 2021 at 13:02:16 UTC, Tejas wrote:
 On Tuesday, 14 December 2021 at 12:04:36 UTC, RazvanN wrote:
 [...]
Then why did my modification work? ```d struct Foo(T){ this(Rhs, this This)(scope Rhs rhs){ } this(scope Foo!(T)* rhs){ //replaced typeof(this) with Foo!T and ref with pointer. Code still works if I retain typeof(this) } } struct Bar{ Foo!int foo; } void main(){ import std.stdio:writeln; Bar bar = Bar(); auto BAR = new Bar(); writeln(bar, "\t", BAR, "\t", *BAR); } ``` Did my modifications ensure that this is not treated as a copy constructor?
Yes, the copy constructor needs to be explicitly defined by passing a ref parameter. Since you are expecting an explicit pointer, the compiler does not see it as a copy constructor and therefore does not try to generate one for Bar.
Dec 14 2021
prev sibling parent reply RazvanN <razvan.nitu1305 gmail.com> writes:
On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote:
 Hello, why does this code fail to compile?

 ```d
 struct Foo(T){
     this(Rhs, this This)(scope Rhs rhs){
     }

     this(ref scope typeof(this) rhs){
     }
 }


 struct Bar{
 	Foo!int foo;
 }

 void main(){
 }
 ```

 error: Segmentation fault (core dumped)
PR: https://github.com/dlang/dmd/pull/13427
Dec 14 2021
parent vit <vit vit.vit> writes:
On Tuesday, 14 December 2021 at 14:40:00 UTC, RazvanN wrote:
 On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote:
 Hello, why does this code fail to compile?

 ```d
 struct Foo(T){
     this(Rhs, this This)(scope Rhs rhs){
     }

     this(ref scope typeof(this) rhs){
     }
 }


 struct Bar{
 	Foo!int foo;
 }

 void main(){
 }
 ```

 error: Segmentation fault (core dumped)
PR: https://github.com/dlang/dmd/pull/13427
Thanks, I got it to work for now: ```d struct Foo(T){ this(Rhs, this This)(auto ref scope Rhs rhs) if(__traits(isRef, rhs) == false){ } this(ref scope typeof(this) rhs){ } } struct Bar{ Foo!int foo; } void main(){ } ```
Dec 14 2021