https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171

mark <markrubn at yahoo dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |markrubn at yahoo dot com

--- Comment #18 from mark <markrubn at yahoo dot com> ---
I'd also like to request a GCC extension to allow reinterpret_cast in a
constexpr. Following are a question, a comment, and a use-case illustrating why
the extension is needed.

Question: I understand that using reinterpret_cast in a constexpr is disallowed
by the C++ standard. *Why* is it disallowed? The only reason I've seen stated
is that "reinterpret_cast may require runtime (hardware) support". That seems
plausible, but a constexpr static_cast from int to double, which requires a far
deeper understanding of the target architecture, is supported. I understand
that int-to-pointer conversion may involve widening, narrowing, or even more
complex and possibly inexpressible semantics (segmented/non-linear memory
architectures), but reinterpret_cast by definition is non-portable and error
prone. Its "use these bits as they are" semantics, with possible truncation or
zero-padding, seems to allow it to be used unambiguously in most normal cases.

Comment: GCC has never been "shy" about adding extensions. Some of them, like
__attribute__((fallthrough) becoming [[fallthrough]], have even eventually made
it into the standards.

Use-case:
It is common practice in embedded microcontrollers to access hardware resources
via reads and writes to specific, fixed memory addresses. I believe this is
generally understood but can provide much more detail if requested.

In addition, microcontrollers are usually very limited in terms of memory and
CPU speed. By using constexpr constructors, extern/static objects are compiled
pre-initialized in the .data segment, eliminating the memory needed for
pre-main() constructor code and the time to execute it.

In GCC 4.8.3, prior to the changes to make GCC standards-compliant as described
in this bug report, the following code would compile the object into .data
segment:

```
class C {
  public:
    constexpr C(
    unsigned* const u)
    :   _u(u)
    {}
    void set() const { *_u = 0x87654321; }
  protected:
    unsigned* const     _u;
};

unsigned* const addr = reinterpret_cast<unsigned*>(0x40000000);
C   c(addr);

int main()
{
    c.set();
}
```

Later versions compile the object into .bss, and also include C::C constructor
code. Attempts to force constexpr construction by changing the above to:

```
constexpr unsigned* const addr = reinterpret_cast<unsigned*>(0x40000000);
```

causes no change with 4.8.3 but results in a fatal "error: value ‘1073741824’
of type ‘unsigned int*’ is not a constant expression" in later versions.

The only workaround I know is to introduce an extra conversion method, which
will then again compile the object into .data with no runtime construction
required:

```
class Addr {
  public:
    constexpr Addr(
    unsigned const u_addr)
    :   _u_addr(u_addr)
    {}
    void set() const { *_u() = 0x87654321; }
  protected:
    volatile unsigned* _u() const { return
reinterpret_cast<unsigned*>(_u_addr);}
    unsigned const      _u_addr;
};

Addr addr(0x40000000);

int main()
{
    addr.set();
}
```

And of course none of this is needed when coding in C instead of C++. The
following struct is placed in .data without any workarounds being required:

```
struct Addr {
    unsigned* const     u;
};

void set(
struct Addr *a)
{
    *(a->u) = 0x87654321;
}

struct Addr     addr = { (unsigned*)0x40000000 };

int main()
{
    set(&addr);
}
```

I firmly believe that C++ offers important improvements over C, with few if any
disadvantages. Many in the embedded programming community feel otherwise ("C++
is obfuscated") and in this example the objection is valid.

Any comments, corrections, or responses -- much less a change so that
-fpermissive allows the reinterpret_cast -- would be welcome. Thank you.

Reply via email to