public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/97432] New: Casting away constness in the drafts [conv.qual] a cv-decomposition exists in the following examples but fails in gcc
@ 2020-10-15  0:10 peifeng2005 at gmail dot com
  2020-10-15  0:12 ` [Bug c++/97432] " peifeng2005 at gmail dot com
  2020-10-15  8:06 ` peifeng2005 at gmail dot com
  0 siblings, 2 replies; 3+ messages in thread
From: peifeng2005 at gmail dot com @ 2020-10-15  0:10 UTC (permalink / raw)
  To: gcc-bugs

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

            Bug ID: 97432
           Summary: Casting away constness in the drafts [conv.qual] a
                    cv-decomposition exists in the following examples but
                    fails in gcc
           Product: gcc
           Version: 11.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: peifeng2005 at gmail dot com
  Target Milestone: ---

In C++, the concept of [casting away
constness](https://timsong-cpp.github.io/cppwp/expr.const.cast#7) is rigorously
defined by the standard. Casts such as `static_cast` and `reinterpret_cast` are
not allowed to cast away constness in the explicit conversion. The definition
of casting away constness heavily relies on the qualification conversion
definition, which says that two types can perform a qualification conversion up
to [similar](https://timsong-cpp.github.io/cppwp/conv.qual#2) type.
`reinterpret_cast` can then perform the cast on the non-similar parts, for
example.

Here is an example also available in [godbolt](https://godbolt.org/z/Y7qEcY):

```c++
struct T{};
struct F{};

void f() {
    const int* const T::* const * const * const x {};

    // pointer to array - works in clang (trunk),
    // works in gcc (trunk)
    reinterpret_cast<int* const T::* const (*) [2]>(x);

    // member pointer to pointer - works in clang (trunk), 
    // fails in gcc (trunk)
    reinterpret_cast<int* const * const * const * const>(x);

    // member pointer to another member pointer type - fails in clang (trunk),
    // fails in gcc (trunk)
    reinterpret_cast<int* const F::* const * const * const>(x);
}
```

Recall the definition of similar. The types at each level must be of the
categories:

> ... each Pi is “pointer to” ([dcl.ptr]), “pointer to member of class Ci of type” ([dcl.mptr]), “array of Ni”, or “array of unknown bound of” ([dcl.array])

To be similar, each Pi must belong to the same category:

> ... corresponding Pi components are either the same or one is “array of Ni” and the other is “array of unknown bound of”

In the first case, array and pointers are NOT similar. GCC and clang correctly
says that the types `X[]` and `X*` are not similar and thus `reinterpret_cast`
kicks in to ignore any const qualifiers past the array (so `const int* const`
could be converted to `int*`). Everything is good.

In the second case, pointers and member pointers should NOT be similar. clang
correctly says that the types are not similar and thus `reinterpret_cast` kicks
in. *GCC says the types are similar and thus we are casting away constness*.
I'm pretty sure GCC is wrong here.

In the third case, we are comparing **two member pointers of different
classes**. Both clang and GCC believes they are similar, but if we carefully
look at the draft, it says **"pointer to member of class Ci of type"**. If
they're of different types, shouldn't we consider them to be not-similar? Are
both clang and gcc wrong here?

By the way, MSVC allows all of the above with no warnings (x64 msvc 19.27 on
godbolt).

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [Bug c++/97432] Casting away constness in the drafts [conv.qual] a cv-decomposition exists in the following examples but fails in gcc
  2020-10-15  0:10 [Bug c++/97432] New: Casting away constness in the drafts [conv.qual] a cv-decomposition exists in the following examples but fails in gcc peifeng2005 at gmail dot com
@ 2020-10-15  0:12 ` peifeng2005 at gmail dot com
  2020-10-15  8:06 ` peifeng2005 at gmail dot com
  1 sibling, 0 replies; 3+ messages in thread
From: peifeng2005 at gmail dot com @ 2020-10-15  0:12 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #1 from Ray Zhang <peifeng2005 at gmail dot com> ---
Providing more context with the first example (also applies for the rest):

1)  // pointer to array - works in clang (trunk),
    // works in gcc (trunk)
    reinterpret_cast<int* const T::* const (*) [2]>(x);

T1: const pointer to const pointer to const pm(T) to const pointer to const U1
T2:       pointer to const array of 2 const pm(T) to const pointer to       U2

In this case, there exists multiple cv-decompositions, as [7.3.6].1 example 1
states:

> [Example 1: The type denoted by the type-id const int ** has three cv-decompositions, taking U as “int”, as “pointer to const int”, and as “pointer to pointer to const int”.

The cv-decompositions we have here for T1 is:

- const pointer to const U1
- const pointer to const pointer to const U1
- const pointer to const pointer to const pm(T) to const U1
- const pointer to const pointer to const pm(T) to const pointer to const U1

If we fulfill one such cv-decompositions, we can consider that reinterpret_cast
will not cast away constness, though U1 and U2 may be nested pointer/array
types of interest.

The unique cv-decomposition that a compiler can decide to take of T1 is:

- const pointer to const U1, where U1 is "pointer to const pm(T) to const
pointer to const int"

The cv-decomposition on T2 can be done similarly:

- const pointer to const U2, where U2 is "array of 2 const pm(T) to const
pointer to int"

Thus, we can perform a reinterpret cast from U1 to U2 without casting away
constness.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [Bug c++/97432] Casting away constness in the drafts [conv.qual] a cv-decomposition exists in the following examples but fails in gcc
  2020-10-15  0:10 [Bug c++/97432] New: Casting away constness in the drafts [conv.qual] a cv-decomposition exists in the following examples but fails in gcc peifeng2005 at gmail dot com
  2020-10-15  0:12 ` [Bug c++/97432] " peifeng2005 at gmail dot com
@ 2020-10-15  8:06 ` peifeng2005 at gmail dot com
  1 sibling, 0 replies; 3+ messages in thread
From: peifeng2005 at gmail dot com @ 2020-10-15  8:06 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #2 from Ray Zhang <peifeng2005 at gmail dot com> ---
Hi, I actually spoke with Richard Smith about the same ticket (since clang was
also involved in the comparison here), and I found that if we were conforming
to the draft, the first case should also fail to compile. The discussion is
linked [here](https://bugs.llvm.org/show_bug.cgi?id=47848).

The issue now is that passing -pedantic-errors into GCC still allows for the
first case to pass. This shouldn't work since we find one such qual conv to
fail (const int vs. int).

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2020-10-15  8:06 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-15  0:10 [Bug c++/97432] New: Casting away constness in the drafts [conv.qual] a cv-decomposition exists in the following examples but fails in gcc peifeng2005 at gmail dot com
2020-10-15  0:12 ` [Bug c++/97432] " peifeng2005 at gmail dot com
2020-10-15  8:06 ` peifeng2005 at gmail dot com

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).