C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Defect Report: Core constant expression inverse of standard conversion sequences

From: David Ledger <davidledger_at_[hidden]>
Date: Mon, 22 Aug 2022 16:54:57 +1000
Well, the dynamic type of the object is unchanging and this appears
glaring inconsistancy with other static_cast behaviour:
```CPP
consteval void fromp()
{
     int v = 10;
     auto lambda = [v](int)
     {
         return v + 32;
     };
     void const * ptr = &lambda;
     auto const * reverse = static_cast<decltype(lambda) const *>(ptr);
// Error: cast from 'const void*' is not allowed
}

void glump()
{
     int v = 10;
     auto lambda = [v](int)
     {
         return v + 32;
     };
     void const * ptr = &lambda;
     auto const * reverse = static_cast<decltype(lambda) const *>(ptr);
// Perfectly fine.
}

int main()
{
     glump();
     fromp();
}
```

To a non-standardese expert, this behaviour seems unexpected. Inverse
conversion sequence isn't changing the dynamic type, before dismissing
it offhand please consider that type erasure through virtual functions
is already achieved through constexpr virtual calls. This appears just
an odd inconcistancy with 5.14.

Regarding impact:

Clang appears to already support this in some special cases, making
exceptions for calls for allocate and source_location, a check for
dynamic type can be made with the existing call to ComputeDynamicType:

clang/lib/AST/ExprConstant.cpp:8877
```CPP
       // 1. We'll allow it in std::allocator::allocate, and anything
which that
       // calls.
       // 2. HACK 2022-03-28: Work around an issue with libstdc++'s
       // <source_location> header. Fixed in GCC 12 and later
(2022-04-??).
       // We'll allow it in the body of
std::source_location::current. GCC's
       // implementation had a parameter of type `void*`, and casts from
       // that back to `const __impl*` in its body.
       if (VoidPtrCastMaybeOK &&
           (Info.getStdAllocatorCaller("allocate") ||
IsDeclSourceLocationCurrent(Info.CurrentCall->Callee))) {
         // Permitted.
       } else {
```

GCC similarly also has to special case to work around the over
constrained clause:
gcc\cp\constexpr.cc:7390
```CPP
     /* [expr.const]: a conversion from type cv void* to a pointer-to-object
        type cannot be part of a core constant expression as a resolution to
        DR 1312. */
     if (TYPE_PTROB_P(type) && TYPE_PTR_P(TREE_TYPE(op)) &&
VOID_TYPE_P(TREE_TYPE(TREE_TYPE(op)))
         /* Inside a call to std::construct_at or to
            std::allocator<T>::{,de}allocate, we permit casting from void*
            because that is compiler-generated code. */
         && !is_std_construct_at(ctx->call) &&
!is_std_allocator_allocate(ctx->call))
     {
       /* Likewise, don't error when casting from void* when OP is
          &heap uninit and similar. */
       tree sop = tree_strip_nop_conversions(op);
```
GCC also has the ability to evaluate dynamic type, atleast according to
this comment:
```CPP
auto obj = cxx_eval_constant_expression (ctx, obj, vc_prvalue,
non_constant_p, overflow_p);
const tree dynamic_type = TREE_TYPE (obj);
```
For example.

On 22/08/2022 2:21 pm, Edward Catmur wrote:
>
> On Mon, 22 Aug 2022, 02:00 Brian Bi via Std-Proposals,
> <std-proposals_at_[hidden]> wrote:
>
>
>
> On Sun, Aug 21, 2022 at 6:06 AM David Ledger via Std-Proposals
> <std-proposals_at_[hidden]> wrote:
>
> Hello W21,
>
> The following example shows a static_cast as per
> [expr.static.cast#7]:
>
> ```CPP
> int v = 10;
> auto lambda = [v](int)
> {
> return v + 32;
> };
> void * ptr = &lambda;
> auto * reverse = static_cast<decltype(lambda) *>(ptr);
> ```
>
> In a constant expression, this is invalid because of
> [expr.const-5.14].
>
> However, in this case it is an inverse of a conversion
> sequence. Since this causes issues when implementing a
> constexpr `std::function_ref` and similar usages I believe the
> clause should be modified to the following:
>
> > (5.14) a conversion from type cv void* to a
> pointer-to-object type<ins>_, other than when this conversion
> is the inverse of any standard conversion sequence_</ins>;
>
>
> I seem to recall some discussion on the predecessor of this
> mailing list about implementation difficulty of allowing casts
> from void* in constant expressions, but I keep failing to find the
> thread.
>
> I'm not sure if your proposed restriction makes it any easier to
> implement. I wish whoever originally posted the post that I'm
> thinking about would post a reply :)
>
>
> Yes, you're not going to get compile time type erasure via function
> pointers in as a defect report. Even virtual functions would be a full
> on proposal.
>

Received on 2022-08-22 06:55:04