February 01, 2015
On 2/1/15 7:11 AM, Iain Buclaw via Digitalmars-d wrote:
> Miniscule divided by meager divided by staggeringly
> infinitesimal is the sort of concept we're trying to get across here.

That could get pretty big. -- Andrei
February 02, 2015
On 2/1/15 9:42 AM, Stefan Frijters wrote:
> So recently I ran into this discrepancy between the behaviour of dmd
> (and gdc) and ldc2:
>
> void test(int[] data)
>    in { assert(data, "data must be non-null."); }

Note, this will soon fail to compile. use assert(data.ptr) instead.

>    body { }
>
> void main() {
>    import std.stdio;
>    int[1] data1;
>    writeln(data1); // [0]
>    test(data1); // Passes
>    assert(data1.ptr !is null);
>    int[0] data0;
>    writeln(data0); // []
>    test(data0); // Passes with dmd and gdc, fails with ldc2 (2.066.1)
>    assert(data0.ptr !is null); // Passes with dmd and gdc, fails with ldc2
> }
>
> I reported this as an issue at
> https://github.com/ldc-developers/ldc/issues/831 and was asked to check
> for a more definite answer. So, in light of recent developments of
> trying to tighten up the D spec, does anyone have any insight what the
> correct behaviour should be, and can it be locked down in the spec?
>
> Currently the D spec says [1]:
>
> ---
>
> Static Arrays
> int[3] s;
> These are analogous to C arrays. Static arrays are distinguished by
> having a length fixed at compile time.
>
> The total size of a static array cannot exceed 16Mb. A dynamic array
> should be used instead for such large arrays.
>
> A static array with a dimension of 0 is allowed, but no space is
> allocated for it. It's useful as the last member of a variable length
> struct, or as the degenerate case of a template expansion.

The lynch pin here is that "it's useful as the last member of a variable length struct." If it's given the address of 0, then it's no longer useful there, so it should take an address of where it is defined.

I'd say this is definitely a bug (and the docs should be clearer on this).

-Steve
February 06, 2015
On Monday, 2 February 2015 at 14:32:16 UTC, Steven Schveighoffer wrote:
> The lynch pin here is that "it's useful as the last member of a variable length struct." If it's given the address of 0, then it's no longer useful there, so it should take an address of where it is defined.

This use case (i.e. as part of a bigger aggregate) already works in LDC.

The issue is specific to zero-size stack allocations. Last time I checked it wasn't possible to do this with LLVM in a sensible way without allocating a non-zero amount of memory. In contrast to the current behavior, this would actually violate the spec as it is worded now.

We can certainly discuss if and how to amend the spec to cater for certain use cases. However, this might be more tricky than it seems at first. For instance, since a pointer to a zero-length static array can never be legally dereferenced, we could just as well always make .ptr return 0xcafebabe for all cases where the array is not part of a larger object. Clearly this seems rather absurd, but how would you want to tighten down the spec?

Recall that in a C-like memory model, no meaning is attached to the numerical value of a pointer per se, and it is undefined behavior to perform arithmetic or comparisons between pointers that refer to different allocations. Formalizing anything beyond that is certainly not a task I want to tackle, and I suspect it would be a portability nightmare regarding modern compiler backends.

Cheers,
David
February 06, 2015
On Sunday, 1 February 2015 at 15:34:48 UTC, Iain Buclaw wrote:
> Regardless of size, a static array should always have an address on
> the stack.  Of course, dereferencing said address is undefined.
>
> You can also consider it a require that although a zero-length static
> array may have an address, it doesn't take up any space either.
>
> Consider:
>
> int[0] data0;
> int[1] data1;
>
>
> Here, you could expect both data0 and data1 to have the same .ptr
> address, but data0.ptr == data1.ptr should not succeed either.

Let's have a look at a related example:

  int[0] data0;
  int[0] data1;

  assert(data0.ptr != data1.ptr); // ???

If you want this assert to succeed, how do you ensure that the addresses are different without allocating at least one byte of stack space (which currently seems to be prohibited by the "does not take up space" clause).

David
February 06, 2015
On Fri, 06 Feb 2015 16:33:49 +0000, David Nadlinger wrote:

> On Sunday, 1 February 2015 at 15:34:48 UTC, Iain Buclaw wrote:
>> Regardless of size, a static array should always have an address on the stack.  Of course, dereferencing said address is undefined.
>>
>> You can also consider it a require that although a zero-length static array may have an address, it doesn't take up any space either.
>>
>> Consider:
>>
>> int[0] data0;
>> int[1] data1;
>>
>>
>> Here, you could expect both data0 and data1 to have the same .ptr address, but data0.ptr == data1.ptr should not succeed either.
> 
> Let's have a look at a related example:
> 
>    int[0] data0;
>    int[0] data1;
> 
>    assert(data0.ptr != data1.ptr); // ???
> 
> If you want this assert to succeed, how do you ensure that the addresses are different without allocating at least one byte of stack space (which currently seems to be prohibited by the "does not take up space" clause).

that's easy: just start assigning increasing addresses from end of ram or start of ram for each "infinitely small" local. as passing it's address is an invalid operation, the only valid thing one can do is compare it with null or some other address, and pass the result of comparison, so it's ok.

February 06, 2015
On Friday, 6 February 2015 at 16:57:11 UTC, ketmar wrote:
> that's easy: just start assigning increasing addresses from end of ram or
> start of ram for each "infinitely small" local. as passing it's address
> is an invalid operation, the only valid thing one can do is compare it
> with null or some other address, and pass the result of comparison, so
> it's ok.

You mean assigning during compilation by keeping some global state around somewhere? I think this would cause all kinds of issues with separate compilation and/or reproducibility of builds.

Using some kind of unique hash identifying the variable declaration might just work, but before starting to forge addresses and hoping that they don't overlap another allocation (on a 32 bit system) or otherwise confuse users, I'd rather be sure that there is value in this behavior in the first place.

David
February 06, 2015
On Fri, 06 Feb 2015 17:37:36 +0000, David Nadlinger wrote:

> On Friday, 6 February 2015 at 16:57:11 UTC, ketmar wrote:
>> that's easy: just start assigning increasing addresses from end of ram or start of ram for each "infinitely small" local. as passing it's address is an invalid operation, the only valid thing one can do is compare it with null or some other address, and pass the result of comparison, so it's ok.
> 
> You mean assigning during compilation by keeping some global state around somewhere? I think this would cause all kinds of issues with separate compilation and/or reproducibility of builds.

only for the current function. it doesn't matter if another function has the same addresses assigned, as it is allowed to reuse stack space. maybe even only for the current code block is enough.

February 06, 2015
"David Nadlinger"  wrote in message news:actxhygoikohznovzbcl@forum.dlang.org...

> Let's have a look at a related example:
>
>    int[0] data0;
>    int[0] data1;
>
>    assert(data0.ptr != data1.ptr); // ???
>
> If you want this assert to succeed, how do you ensure that the addresses are different without allocating at least one byte of stack space (which currently seems to be prohibited by the "does not take up space" clause).

I seriously doubt the intent of that line in the spec was meant to apply to stack-allocated zero length static arrays.  I think we should just change it so that we are allowed to allocate some non-zero amount of stack space for the array and give it a valid pointer.  Layout matters when used in a struct, not so much when it's on the stack. 

February 06, 2015
On 2/6/15 11:15 AM, David Nadlinger wrote:
> On Monday, 2 February 2015 at 14:32:16 UTC, Steven Schveighoffer wrote:
>> The lynch pin here is that "it's useful as the last member of a
>> variable length struct." If it's given the address of 0, then it's no
>> longer useful there, so it should take an address of where it is defined.
>
> This use case (i.e. as part of a bigger aggregate) already works in LDC.
>
> The issue is specific to zero-size stack allocations. Last time I
> checked it wasn't possible to do this with LLVM in a sensible way
> without allocating a non-zero amount of memory. In contrast to the
> current behavior, this would actually violate the spec as it is worded now.

What about a closure? Isn't that a struct allocated on the heap?

-Steve
February 06, 2015
On 6 February 2015 at 16:33, David Nadlinger via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On Sunday, 1 February 2015 at 15:34:48 UTC, Iain Buclaw wrote:
>>
>> Regardless of size, a static array should always have an address on the stack.  Of course, dereferencing said address is undefined.
>>
>> You can also consider it a require that although a zero-length static array may have an address, it doesn't take up any space either.
>>
>> Consider:
>>
>> int[0] data0;
>> int[1] data1;
>>
>>
>> Here, you could expect both data0 and data1 to have the same .ptr address, but data0.ptr == data1.ptr should not succeed either.
>
>
> Let's have a look at a related example:
>
>   int[0] data0;
>   int[0] data1;
>
>   assert(data0.ptr != data1.ptr); // ???
>
> If you want this assert to succeed, how do you ensure that the addresses are different without allocating at least one byte of stack space (which currently seems to be prohibited by the "does not take up space" clause).
>

For debugging purposes, it must have a position on the stack pointer. For semantic purposes, comparing it as being equal to another value must be false.