Jump to page: 1 2
Thread overview
[Issue 10763] New: (&x)[0 .. 1] doesn't work in CTFE
Aug 05, 2013
Nils
Aug 12, 2013
Don
Aug 12, 2013
timon.gehr@gmx.ch
Aug 13, 2013
Don
Aug 13, 2013
timon.gehr@gmx.ch
Aug 19, 2013
Don
Aug 19, 2013
timon.gehr@gmx.ch
Aug 19, 2013
Iain Buclaw
Aug 19, 2013
Don
Aug 19, 2013
Iain Buclaw
Aug 19, 2013
Iain Buclaw
Aug 19, 2013
Iain Buclaw
Oct 10, 2013
Iain Buclaw
August 05, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=10763

           Summary: (&x)[0 .. 1] doesn't work in CTFE
           Product: D
           Version: unspecified
          Platform: All
        OS/Version: All
            Status: NEW
          Keywords: CTFE
          Severity: enhancement
          Priority: P2
         Component: DMD
        AssignedTo: nobody@puremagic.com
        ReportedBy: nilsbossung@googlemail.com


--- Comment #0 from Nils <nilsbossung@googlemail.com> 2013-08-05 15:42:46 PDT ---
static assert({
    int x;
    int[] a = (&x)[0 .. 1];

    return true;
}());

Error: pointer & x cannot be sliced at compile time (it does not point to an
array)

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
August 12, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=10763



--- Comment #1 from Don <clugdbug@yahoo.com.au> 2013-08-12 14:16:59 PDT ---
This restriction is intentional. It's a consequence of strictly enforcing C's
pointer arithmetic rules.
You can only slice a pointer that you can perform pointer arithmetic on.

Where x is a variable, C does not guarantee that &x + 1 is a legal address. (For example, it might be 0, if x is at the end of the address space).

(Enforcing C's pointer arithmetic enormously simplifies the implementation. Allowing this would create a huge number of special cases).

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
August 12, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=10763


timon.gehr@gmx.ch changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |timon.gehr@gmx.ch


--- Comment #2 from timon.gehr@gmx.ch 2013-08-12 14:59:00 PDT ---
What kind of special cases? (The above code works in my own implementation.)

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
August 13, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=10763



--- Comment #3 from Don <clugdbug@yahoo.com.au> 2013-08-12 17:13:15 PDT ---
It's basically the same as issue 10266.
The corner cases arise if you still disallow &x + 1. My guess is that you're
allowing it in your implementation?

The problem with allowing it is that we're departing from C. And there's annoying things like:

// global scope
int x;
int *p = &x + 1; // points to junk! - must not compile


Is there really a use case for this unsafe behaviour?

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
August 13, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=10763



--- Comment #4 from timon.gehr@gmx.ch 2013-08-12 19:01:50 PDT ---
(In reply to comment #3)
> It's basically the same as issue 10266.

Issue 10266 additionally requests allowing reinterpret-casts between T* and T[1]* (my implementation currently rejects this, but allowing it would be easy.)

> The corner cases arise if you still disallow &x + 1. My guess is that you're
> allowing it in your implementation?
> ...

Yes, but dereferencing it is an error. Subtracting one results in the address of x.

> The problem with allowing it is that we're departing from C.

Does C actually disallow adding 0 to a pointer to a local variable? That's what the example is doing. Furthermore, I don't see what the restriction buys in terms of implementation effort. Every program can be rewritten to only contain arrays.

> And there's annoying things like:
> 
> // global scope
> int x;
> int *p = &x + 1; // points to junk! - must not compile
> 

Agreed, but I think this is not closely related. DMD already allows creating invalid addresses in CTFE by other means.

> 
> Is there really a use case for this unsafe behaviour?

Make more code CTFE-able.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
August 19, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=10763



--- Comment #5 from Don <clugdbug@yahoo.com.au> 2013-08-19 02:37:33 PDT ---
(In reply to comment #4)
> (In reply to comment #3)
> > It's basically the same as issue 10266.
> 
> Issue 10266 additionally requests allowing reinterpret-casts between T* and T[1]* (my implementation currently rejects this, but allowing it would be easy.)
> 
> > The corner cases arise if you still disallow &x + 1. My guess is that you're
> > allowing it in your implementation?
> > ...
> 
> Yes, but dereferencing it is an error. Subtracting one results in the address of x.

That is not the issue. The problem is that in C, simply creating the pointer is
undefined behaviour. No dereferencing is involved.
Note that is undefined behaviour, it's not even implementation-specific
behaviour!
Simply storing an invalid pointer into a pointer register may generate a
hardware exception on some systems.

In C, you are not permitted to do pointer arithmetic unless the pointer points to an array, or one-past-the-end-of-an-array.

> > The problem with allowing it is that we're departing from C.
> 
> Does C actually disallow adding 0 to a pointer to a local variable? That's what the example is doing.

I'm not sure if that's legal or not. I suspect not, though I think it would always work in practice. But adding 1 to a pointer to a local variable is definitely illegal, and there are systems where it will not work.

So the end of the slice is problematic.

> > Is there really a use case for this unsafe behaviour?
> 
> Make more code CTFE-able.

But it's undefined behaviour.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
August 19, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=10763



--- Comment #6 from timon.gehr@gmx.ch 2013-08-19 03:25:14 PDT ---
(In reply to comment #5)
> (In reply to comment #4)
> > (In reply to comment #3)
> > ...
> > > The corner cases arise if you still disallow &x + 1. My guess is that you're
> > > allowing it in your implementation?
> > > ...
> > 
> > Yes, but dereferencing it is an error. Subtracting one results in the address of x.
> 
> That is not the issue. The problem is that in C, simply creating the pointer is undefined behaviour.

I guess I'll update my implementation eventually to disallow this. (Other related limitations are that it currently allows escaping addresses to locals and simply closes over them, array appends may cause non-determinism and pointers can be freely compared.)

> ...
> > > Is there really a use case for this unsafe behaviour?
> > 
> > Make more code CTFE-able.
> 
> But it's undefined behaviour.

There is not really a reason why (&x)[0..1] should be UB. But I guess if you want to keep C behaviour and also keep the invariant that slices always point to arrays, this is indeed not fixable.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
August 19, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=10763


Iain Buclaw <ibuclaw@ubuntu.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |ibuclaw@ubuntu.com


--- Comment #7 from Iain Buclaw <ibuclaw@ubuntu.com> 2013-08-19 03:42:54 PDT ---
(In reply to comment #3)
> It's basically the same as issue 10266.
> The corner cases arise if you still disallow &x + 1. My guess is that you're
> allowing it in your implementation?
> 
> The problem with allowing it is that we're departing from C. And there's annoying things like:
> 
> // global scope
> int x;
> int *p = &x + 1; // points to junk! - must not compile
> 
> 
> Is there really a use case for this unsafe behaviour?

Only one would be in std.math if we want to make the elementary functions CTFE-able (we've discussed this before).

But yes, I think that it is right to disallow it, as there is no clean way to slice up basic types into an array and guarantee ie: format or endian correctness at compile time (cross-compilers, for instance).

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
August 19, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=10763



--- Comment #8 from Don <clugdbug@yahoo.com.au> 2013-08-19 04:48:39 PDT ---
(In reply to comment #7)
> (In reply to comment #3)
> > It's basically the same as issue 10266.
> > The corner cases arise if you still disallow &x + 1. My guess is that you're
> > allowing it in your implementation?
> > 
> > The problem with allowing it is that we're departing from C. And there's annoying things like:
> > 
> > // global scope
> > int x;
> > int *p = &x + 1; // points to junk! - must not compile
> > 
> > 
> > Is there really a use case for this unsafe behaviour?
> 
> Only one would be in std.math if we want to make the elementary functions CTFE-able (we've discussed this before).

That's why my proposed solution for that is to allow only the complete expression, where the pointer is instantly dereferenced:

(cast(ulong *)cast(void *)&f)[0];

and it really only needs to be allowed for 80-bit reals, since casting float<->int and double<->long is already supported.

The minimal operations are:
- significand  <-> ulong
- sign  + exponent <-> ushort

That would give us four special-case hacks which are x87 specific. Effectively they are intrinsics with ugly syntax.

The existing code could be modified slightly to only use those four operations, with no performance penalty.

> But yes, I think that it is right to disallow it, as there is no clean way to slice up basic types into an array and guarantee ie: format or endian correctness at compile time (cross-compilers, for instance).

It's an ugly area.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
August 19, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=10763



--- Comment #9 from Iain Buclaw <ibuclaw@ubuntu.com> 2013-08-19 05:29:09 PDT ---
(In reply to comment #8)
> (In reply to comment #7)
> > (In reply to comment #3)
> > > It's basically the same as issue 10266.
> > > The corner cases arise if you still disallow &x + 1. My guess is that you're
> > > allowing it in your implementation?
> > > 
> > > The problem with allowing it is that we're departing from C. And there's annoying things like:
> > > 
> > > // global scope
> > > int x;
> > > int *p = &x + 1; // points to junk! - must not compile
> > > 
> > > 
> > > Is there really a use case for this unsafe behaviour?
> > 
> > Only one would be in std.math if we want to make the elementary functions CTFE-able (we've discussed this before).
> 
> That's why my proposed solution for that is to allow only the complete expression, where the pointer is instantly dereferenced:
> 
> (cast(ulong *)cast(void *)&f)[0];
> 
> and it really only needs to be allowed for 80-bit reals, since casting float<->int and double<->long is already supported.
> 

And (speaking as someone who stubbed out your implementation of float<->int and double<->long cast) the only reason why it's supported is because the backend I implement against can (thankfully) do re-interpreted native casts between basic types such as integer, float, complex and vectors.

You will need to support all reals that have support in std.math. This includes
64-bit, 80-bit, 96-bit (really just 80-bit), 128-bit (likewise), and 128-bit
(quadruple).  There are only three supported formats really... (double-double
will have to keep with partial support for the time being, sorry PPC!)

> The minimal operations are:
> - significand  <-> ulong
> - sign  + exponent <-> ushort
> 
> That would give us four special-case hacks which are x87 specific. Effectively they are intrinsics with ugly syntax.
> 

I veto any new addition that is x87 specific - or, more accurately endian specific.

Remember its:

version(BigEndian)
  short sign_exp = (cast(ushort*)&x)[0];
else
  short sign_exp = (cast(ushort*)&x)[5];

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
« First   ‹ Prev
1 2