On Mon, 22 Aug 2022 at 07:55, David Ledger <davidledger@live.com.au> wrote:

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.

I'm sure it's feasible (and thanks for correcting me about virtual functions); I'm just saying that static_cast from void* to an object's dynamic type is going to require a paper. The lack of a feature is not grounds for a DR. 

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.

Great, hopefully this should smooth the way.

However, I can see some potential issues; just off the top of my head:

- doesn't this allow bypassing access checks on inheritance - cast to void* then to a private first base? Perhaps this should be restricted to casting back to the most derived type?
- what if there is more than one object with the same type at an address (specifically, if one provides storage for the other) - which object is referenced by the converted pointer?

Or when you say that the cast should be the "inverse of a standard conversion sequence", do you mean that the void* pointer should track its provenance and allow only conversions that unwind that provenance? Because I'm not sure that compilers implement that currently.

On 22/08/2022 2:21 pm, Edward Catmur wrote:

On Mon, 22 Aug 2022, 02:00 Brian Bi via Std-Proposals, <std-proposals@lists.isocpp.org> wrote:


On Sun, Aug 21, 2022 at 6:06 AM David Ledger via Std-Proposals <std-proposals@lists.isocpp.org> 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.