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

            Bug ID: 105865
           Summary: false positive expression static_cast
                    pointer-to-member upcast in constexpr constructor
           Product: gcc
           Version: 12.1.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: acox at reliablecontrols dot com
  Target Milestone: ---

G++ doesn't determine that an upcast on a pointer-to-member-function in a
constexpr constructor is valid when used in a constexpr context. No options to
g++ are needed, and there shouldn't be any preprocessing.

struct H
{
    template <class T>
    using fn = int (T::*)(int v) const;

    int a(int v) const { return v+40; }
    int b(int v) const { return v+20; }

    struct beta {
        fn<H> mX;

        template <class T>
        constexpr beta(fn<T> x): mX{static_cast<fn<H>>(x)} {}
    };
};

struct I : public H{
    int c(int v) const { return v+40; }
};

int main()
{
    constexpr H::beta x {&I::c};
}

On newer versions it will give this error message which is visually incorrect
because it's a static_cast and not a reinterpret_cast. (this is from 12.1)

<source>:29:31: error: 'constexpr H::beta::beta(H::fn<T>) [with T = I; H::fn<T>
= unsigned int (I::*)(unsigned int) const]' called in a constant expression
   29 |     constexpr H::beta x {&I::c};
      |                               ^
<source>:19:19: note: 'constexpr H::beta::beta(H::fn<T>) [with T = I; H::fn<T>
= unsigned int (I::*)(unsigned int) const]' is not usable as a 'constexpr'
function because:
   19 |         constexpr beta(fn<T> x): mX{static_cast<fn<H>>(x)} {}
      |                   ^~~~
<source>:19:37: error: 'reinterpret_cast' is not a constant expression
   19 |         constexpr beta(fn<T> x): mX{static_cast<fn<H>>(x)} {}
      |                                     ^~~~~~~~~~~~~~~~~~~~~

On older versions it doesn't give any indication of what went wrong. Which is
annoying with more constructor arguments and possible implicit converting
constructors. (This is from 9.4)


<source>:29:31: error: 'constexpr H::beta::beta(H::fn<T>) [with T = I; H::fn<T>
= unsigned int (I::*)(unsigned int) const; uint32_t = unsigned int]' called in
a constant expression
   29 |     constexpr H::beta x {&I::c};
      |                               ^
<source>:19:19: note: 'constexpr H::beta::beta(H::fn<T>) [with T = I; H::fn<T>
= unsigned int (I::*)(unsigned int) const; uint32_t = unsigned int]' is not
usable as a 'constexpr' function because:
   19 |         constexpr beta(fn<T> x): mX{static_cast<fn<H>>(x)} {}
      |                   ^~~~

The issue goes away when you restructure the program to do the cast outside of
the constructor. However, if you're intending to construct many objects at
compile time this method can be cumbersome and overly verbose.

This problem was previously described here:
https://stackoverflow.com/q/46818864
I have reproduced it in a live environment here https://godbolt.org/z/vv1ocd77o
to illustrate it does work with clang

Version information (gcc -v)
Target: x86_64-linux-gnu
Configured with: ../gcc-12.1.0/configure
--prefix=/opt/compiler-explorer/gcc-build/staging --build=x86_64-linux-gnu
--host=x86_64-linux-gnu --target=x86_64-linux-gnu --disable-bootstrap
--enable-multiarch --with-abi=m64 --with-multilib-list=m32,m64,mx32
--enable-multilib --enable-clocale=gnu
--enable-languages=c,c++,fortran,ada,go,d --enable-ld=yes --enable-gold=yes
--enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-linker-build-id
--enable-lto --enable-plugins --enable-threads=posix
--with-pkgversion=Compiler-Explorer-Build-gcc--binutils-2.38
--enable-libstdcxx-backtrace=yes
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 12.1.0 (Compiler-Explorer-Build-gcc--binutils-2.38) 
COLLECT_GCC_OPTIONS='-fdiagnostics-color=always' '-g' '-o' '/app/output.s'
'-masm=intel' '-S' '-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
'-dumpdir' '/app/'

/opt/compiler-explorer/gcc-12.1.0/bin/../libexec/gcc/x86_64-linux-gnu/12.1.0/cc1plus
-quiet -v -imultiarch x86_64-linux-gnu -iprefix
/opt/compiler-explorer/gcc-12.1.0/bin/../lib/gcc/x86_64-linux-gnu/12.1.0/
-D_GNU_SOURCE <source> -quiet -dumpdir /app/ -dumpbase output.cpp -dumpbase-ext
.cpp -masm=intel -mtune=generic -march=x86-64 -g -version
-fdiagnostics-color=always -o /app/output.s
GNU C++17 (Compiler-Explorer-Build-gcc--binutils-2.38) version 12.1.0
(x86_64-linux-gnu)
        compiled by GNU C version 7.5.0, GMP version 6.2.1, MPFR version 4.1.0,
MPC version 1.2.1, isl version isl-0.24-GMP

Reply via email to