Thread overview
crash when using &this in struct constructor
Jul 16, 2018
Eric
Jul 16, 2018
Eric
Jul 16, 2018
Adam D. Ruppe
Jul 16, 2018
Eric
Jul 16, 2018
H. S. Teoh
Jul 18, 2018
baz
Jul 18, 2018
baz
Jul 18, 2018
Eric
Jul 16, 2018
Ali Çehreli
July 16, 2018
This makes the compiler crash. Is it illegal code?

struct List {
  private List* head;
  private List* tail;

  this(int x) {
    head = null;
    tail = &this; // <-- crasher
  }
}

List2 ls = 2;

July 16, 2018
Pasted slightly wrong code, last line should be:
List ls = 2;

Question still stands.

July 16, 2018
On Monday, 16 July 2018 at 22:08:34 UTC, Eric wrote:
> This makes the compiler crash. Is it illegal code?

Yes, a struct can be moved at any time by the compiler which means pointers to it can be invalidated at random.

Unless you always allocate it externally yourself...
July 16, 2018
On Mon, Jul 16, 2018 at 10:08:34PM +0000, Eric via Digitalmars-d-learn wrote:
> This makes the compiler crash. Is it illegal code?
> 
> struct List {
>   private List* head;
>   private List* tail;
> 
>   this(int x) {
>     head = null;
>     tail = &this; // <-- crasher
>   }
> }
> 
> List2 ls = 2;

It's not illegal per se, but a very, very bad idea in general, because in D, structs are expected to be int-like POD values that can be freely copied/moved around by the compiler.  More specifically, when structs are passed into functions or returned from functions, they may be moved around.  Which means internal pointers will wind up being wrong.

This can be somewhat alleviated with a postblit ctor, but it doesn't cover all the cases, and the above code looks like one of the cases where it will likely not cover all cases.  So yeah, you're probably getting a dangling pointer because of this.

If you need something that doesn't move around, either allocate the struct on the heap using `new`, or use classes instead.  Note that while the former will work, it will still require care, because passing the resulting struct around will pass it by value, and you end up with the same dangling pointer problem again.  So you really want to be using classes for this.

Or rethink your algorithms so that they don't depend on having internal pointers.


T

-- 
Give me some fresh salted fish, please.
July 16, 2018
On Monday, 16 July 2018 at 22:16:10 UTC, Adam D. Ruppe wrote:
> On Monday, 16 July 2018 at 22:08:34 UTC, Eric wrote:
>> This makes the compiler crash. Is it illegal code?
>
> Yes, a struct can be moved at any time by the compiler which means pointers to it can be invalidated at random.
>
> Unless you always allocate it externally yourself...

I know that. At the moment I disable the postblit and use an init():

class Test {
  List ls;

  this() {
    ls.init();
  }
}

But I want to be able to write something less verbose like:

class Test {
  List ls = 1;
}

And I was hoping a this(int) constructor would happen in place, not move things around.


July 16, 2018
On 07/16/2018 03:08 PM, Eric wrote:
> This makes the compiler crash.

Always a compiler bug:

  https://issues.dlang.org/show_bug.cgi?id=19089

Ali
July 18, 2018
On Monday, 16 July 2018 at 22:21:12 UTC, H. S. Teoh wrote:
> On Mon, Jul 16, 2018 at 10:08:34PM +0000, Eric via Digitalmars-d-learn wrote:
>> [...]
>
> It's not illegal per se, but a very, very bad idea in general, because in D, structs are expected to be int-like POD values that can be freely copied/moved around by the compiler.  More specifically, when structs are passed into functions or returned from functions, they may be moved around.  Which means internal pointers will wind up being wrong.
>
> [...]

Moving doesn't seem to be the issue here. Despite of the ICE, this code shouldn't compile, unless "&this" is allowed at compile-time.
July 18, 2018
On Wednesday, 18 July 2018 at 11:27:33 UTC, baz@dlang-community wrote:
> On Monday, 16 July 2018 at 22:21:12 UTC, H. S. Teoh wrote:
>> On Mon, Jul 16, 2018 at 10:08:34PM +0000, Eric via Digitalmars-d-learn wrote:
>>> [...]
>>
>> It's not illegal per se, but a very, very bad idea in general, because in D, structs are expected to be int-like POD values that can be freely copied/moved around by the compiler.  More specifically, when structs are passed into functions or returned from functions, they may be moved around.  Which means internal pointers will wind up being wrong.
>>
>> [...]
>
> Moving doesn't seem to be the issue here. Despite of the ICE, this code shouldn't compile, unless "&this" is allowed at compile-time.

still with .init() trick this works, so im' not super sure...
July 18, 2018
On Wednesday, 18 July 2018 at 11:35:40 UTC, baz wrote:
> On Wednesday, 18 July 2018 at 11:27:33 UTC, baz@dlang-community wrote:
>> On Monday, 16 July 2018 at 22:21:12 UTC, H. S. Teoh wrote:
>>> On Mon, Jul 16, 2018 at 10:08:34PM +0000, Eric via Digitalmars-d-learn wrote:
>>>> [...]
>>>
>>> It's not illegal per se, but a very, very bad idea in general, because in D, structs are expected to be int-like POD values that can be freely copied/moved around by the compiler.  More specifically, when structs are passed into functions or returned from functions, they may be moved around.  Which means internal pointers will wind up being wrong.
>>>
>>> [...]
>>
>> Moving doesn't seem to be the issue here. Despite of the ICE, this code shouldn't compile, unless "&this" is allowed at compile-time.
>
> still with .init() trick this works, so im' not super sure...

NVM the .init() trick. Specs are clear : it's a global so it's evaluated at compile time (https://dlang.org/spec/declaration.html#global_static_init)

Example code should not compile.
July 18, 2018
On Wednesday, 18 July 2018 at 12:10:18 UTC, baz wrote:

> Specs are clear : it's a global so it's evaluated at compile time (https://dlang.org/spec/declaration.html#global_static_init)
>
> Example code should not compile.

Indeed. Inside a function it does actually work.
And ofcourse for

class Test {
 List ls = 1;
}

it's going to make a static initializer which is then copied during construction of Test, so that's never going to work with the &this.