The following code fails to compile for reasons cited
in the comments. However, since placement new only
affects a non-static member variable, it's unclear why
the placement new use is not allowed.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussio...@isocpp.org.
To post to this group, send email to std-dis...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-discussion/.
On 2015–04–13, at 6:16 PM, Richard Smith <ric...@metafoo.co.uk> wrote:On Mon, Apr 13, 2015 at 2:35 AM, Larry Evans <cpplj...@suddenlink.net> wrote:The following code fails to compile for reasons cited
in the comments. However, since placement new only
affects a non-static member variable, it's unclear why
the placement new use is not allowed.Placement new is not allowed because it would allow constant expression evaluation to interact with the underlying storage of objects (which need not exist and need not be modeled the same way as at runtime).
On 2015–04–13, at 6:16 PM, Richard Smith <ric...@metafoo.co.uk> wrote:On Mon, Apr 13, 2015 at 2:35 AM, Larry Evans <cpplj...@suddenlink.net> wrote:The following code fails to compile for reasons cited
in the comments. However, since placement new only
affects a non-static member variable, it's unclear why
the placement new use is not allowed.Placement new is not allowed because it would allow constant expression evaluation to interact with the underlying storage of objects (which need not exist and need not be modeled the same way as at runtime).Put another way, new( char_ptr ) Thing intrinsically includes an operation like reinterpret_cast< Thing * >( char_ptr ). The cast is illegal because you can still access the char_ptr array, and new is illegal by implication.I wonder if it would be feasible to poison the array to sidestep the issue. Something like, in a constant evaluation context:1. Casting to void* is not allowed except from a char* value referencing the first element of an array which is a constant expression in the current context. (Note, the relevant reinterpret_cast is defined in terms of static_casts to and from void*.)2. Casting from cv void* is not allowed unless the value was produced by a cast from char*.3. Accessing an array with a subobject (character) that has participated in such a cast in not allowed.4. Casting the array again to a different type is not allowed.Also allowing the opposite cast, from an object pointer to a char* invisibly associated with its type, would provide consistency and enable constexpr std::addressof, which is currently a minor hole.
However, having constructed such an object, you wouldn’t be able to destroy it because there are no constexpr explicit destructor calls. (Pedantically, the standard only says pseudo-destructor calls (§5.2.4) are not allowed, and those are a different animal than explicit destructor calls (§12.4/13), but that’s certainly a defect.)
Those would need to be allowed as well, and then the interpreter has to keep a bit of state for each object to remember whether it’s already been destroyed.I think just a few pieces of additional state would be sufficient to get this working:1. For the representation of char array constants, remember what object (if any) it’s been cast to or from. This reference could be stored in place of the array value. For extra generosity, provide for a sequence of objects at offsets within the array.2. For all other constant, complete objects, store a potential reference to the (inaccessible, stubbed-out) char array of its object representation.3. Provide some means of navigating from subobjects to complete objects.4. Let each void * constant value have an underlying char * value.5. Allow char * constant values to refer to any target, not necessarily a char.
Support for all this would be somewhat useful alone, and a step toward predynamic storage. The added complexity is substantial, but still less than emulating all object representation, and nothing to kill performance. Unless I’ve missed something.
On 2015–04–14, at 7:55 AM, Richard Smith <ric...@metafoo.co.uk> wrote:I think the easiest way to get a constexpr std::addressof is just for the library to mark it constexpr. Implementations can easily support it as a builtin (Clang has had a constexpr __builtin_addressof for quite some time).
However, having constructed such an object, you wouldn’t be able to destroy it because there are no constexpr explicit destructor calls. (Pedantically, the standard only says pseudo-destructor calls (§5.2.4) are not allowed, and those are a different animal than explicit destructor calls (§12.4/13), but that’s certainly a defect.)An explicit destructor call would be an invocation of a function that is not constexpr, so should be covered by the second bullet in 5.20.
Those would need to be allowed as well, and then the interpreter has to keep a bit of state for each object to remember whether it’s already been destroyed.I think just a few pieces of additional state would be sufficient to get this working:1. For the representation of char array constants, remember what object (if any) it’s been cast to or from. This reference could be stored in place of the array value. For extra generosity, provide for a sequence of objects at offsets within the array.2. For all other constant, complete objects, store a potential reference to the (inaccessible, stubbed-out) char array of its object representation.3. Provide some means of navigating from subobjects to complete objects.4. Let each void * constant value have an underlying char * value.5. Allow char * constant values to refer to any target, not necessarily a char.The above is not sufficient for Clang's implementation, which represents a pointer or reference as a path (sequence of members, bases, array elements) from a complete object (a declaration or temporary creation, plus optionally a handle to a particular function invocation), and your new object is not reachable in such a manner. I don't know how other implementations represent values during constexpr evaluation, but I wouldn't be surprised if the above is insufficient for them in some way, too.
I think the complexity (not just in implementation, but also in specification and user-facing language semantics) is probably too great to support this as a special case. If this could be made to work more generally, that might help to justify the complexity, but there are limits to how far we can push constexpr and retain a strong phase distinction and a simple semantic model.
It's not just std::addressof that is affected; std::numeric_limits<FloatType>::infinity() and friends are as well, and those are mandated to be constexpr already. GCC libstdc++ uses compiler magic in the form of __builtin_hugevalf() to do that currently, even though current GCC allows reinterpret_cast and fun with unions in constexpr. No idea about Clang and libcxx, or MSVC 2015, other than that MSVC 2015 lets you get away with constexpr reinterpret_cast shenanigans and Clang rightfully doesn't.
Melissa
On Monday, April 13, 2015 at 4:55:30 PM UTC-7, Richard Smith wrote:
> On Mon, Apr 13, 2015 at 9:56 AM, David Krauss <pot...@gmail.com> wrote:
> > Also allowing the opposite cast, from an object pointer to a char* invisibly associated with its type, would provide consistency and enable constexpr std::addressof, which is currently a minor hole.
>
>
> I think the easiest way to get a constexpr std::addressof is just for the library to mark it constexpr. Implementations can easily support it as a builtin (Clang has had a constexpr __builtin_addressof for quite some time).
It's not just std::addressof that is affected; std::numeric_limits<FloatType>::infinity() and friends are as well, and those are mandated to be constexpr already. GCC libstdc++ uses compiler magic in the form of __builtin_hugevalf() to do that currently,
even though current GCC allows reinterpret_cast and fun with unions in constexpr.
No idea about Clang and libcxx, or MSVC 2015, other than that MSVC 2015 lets you get away with constexpr reinterpret_cast shenanigans and Clang rightfully doesn't.
Melissa