Thread overview
template ctor overload Segmentation fault
Dec 12, 2021
vit
Dec 12, 2021
Imperatorn
Dec 12, 2021
vit
Dec 13, 2021
Tejas
Dec 13, 2021
user1234
Dec 14, 2021
RazvanN
Dec 14, 2021
Tejas
Dec 14, 2021
RazvanN
Dec 14, 2021
RazvanN
Dec 14, 2021
vit
December 12, 2021

Hello, why does this code fail to compile?

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)

December 12, 2021

On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote:

>

Hello, why does this code fail to compile?

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?

December 12, 2021

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?

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:

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.

December 13, 2021

On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote:

>

Hello, why does this code fail to compile?

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.

December 13, 2021

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?

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:

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:

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.

December 14, 2021

On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote:

>

Hello, why does this code fail to compile?

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

December 14, 2021

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?

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?

December 14, 2021

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?

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.

December 14, 2021

On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote:

>

Hello, why does this code fail to compile?

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

December 14, 2021

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?

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:

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(){
}