Bug 86970 - Rejected constexpr expression involving lambdas and inheritance, "use of this in a constant expression"
Summary: Rejected constexpr expression involving lambdas and inheritance, "use of this...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 8.1.0
: P3 normal
Target Milestone: 10.0
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
Depends on:
Blocks: constexpr
  Show dependency treegraph
 
Reported: 2018-08-16 04:29 UTC by Justin Bassett
Modified: 2023-12-15 23:33 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work: 10.0
Known to fail: 9.4.0
Last reconfirmed: 2018-08-22 00:00:00


Attachments
The .ii file from -save-temps (77.60 KB, text/plain)
2018-08-16 04:29 UTC, Justin Bassett
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Justin Bassett 2018-08-16 04:29:20 UTC
Created attachment 44549 [details]
The .ii file from -save-temps

The following code fails to compile under g++-8:

Command: g++-8 -Wall -Wextra -std=c++17 min.cpp

Compiler Explorer link: https://godbolt.org/g/iByFDC

#include <tuple>
#include <utility>

namespace ns {
    template <typename A>
    class Foo : private A
    {
    public:
        template <typename FA>
        explicit constexpr Foo(FA&& a)
            : A{std::forward<FA>(a)}
        {}
    };

    template <typename A>
    Foo(A)->Foo<A>;

    template <typename T>
    constexpr auto frobnicate(T&& val)
    {
        return [val = std::forward<T>(val)] {};
    }

    template <typename A, typename B>
    class Bar
    {
        A a;
        std::tuple<B> b;

    public:
        template <typename FA, typename FB>
        explicit constexpr Bar(FA&& a, FB&& b)
            : a{a}
            , b{b}
        {}
    };

    template <typename A, typename B>
    Bar(A, B)->Bar<A, B>;

    constexpr auto Baz = ns::Foo{ns::frobnicate(ns::Bar{[] {}, [](int) {}})};
}

Compiler diagnostics:

min.cpp:41:76: error: ‘constexpr ns::Foo<A>::Foo(FA&&) [with FA = ns::frobnicate(T&&) [with T = ns::Bar<ns::<lambda()>, ns::<lambda(int)> >]::<lambda()>; A = ns::frobnicate(T&&) [with T = ns::Bar<ns::<lambda()>, ns::<lambda(int)> >]::<lambda()>]’ called in a constant expression
     constexpr auto Baz = ns::Foo{ns::frobnicate(ns::Bar{[] {}, [](int) {}})};
                                                                            ^
min.cpp:10:28: note: ‘constexpr ns::Foo<A>::Foo(FA&&) [with FA = ns::frobnicate(T&&) [with T = ns::Bar<ns::<lambda()>, ns::<lambda(int)> >]::<lambda()>; A = ns::frobnicate(T&&) [with T = ns::Bar<ns::<lambda()>, ns::<lambda(int)> >]::<lambda()>]’ is not usable as a ‘constexpr’ function because:
         explicit constexpr Foo(FA&& a)
                            ^~~
min.cpp:11:36: error: call to non-‘constexpr’ function ‘ns::frobnicate(T&&) [with T = ns::Bar<ns::<lambda()>, ns::<lambda(int)> >]::<lambda()>::<lambda>(ns::frobnicate(T&&) [with T = ns::Bar<ns::<lambda()>, ns::<lambda(int)> >]::<lambda()>&&)’
             : A{std::forward<FA>(a)}
                                    ^
min.cpp:21:46: note: ‘ns::frobnicate(T&&) [with T = ns::Bar<ns::<lambda()>, ns::<lambda(int)> >]::<lambda()>::<lambda>(ns::frobnicate(T&&) [with T = ns::Bar<ns::<lambda()>, ns::<lambda(int)> >]::<lambda()>&&)’ is not usable as a ‘constexpr’ function because:
         return [val = std::forward<T>(val)] {};
                                              ^
min.cpp:21:46: error: use of ‘this’ in a constant expression

System info (from running `g++-8 -v`):

Using built-in specs.
COLLECT_GCC=g++-8
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/8/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 8.1.0-5ubuntu1~16.04' --with-bugurl=file:///usr/share/doc/gcc-8/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-8 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 8.1.0 (Ubuntu 8.1.0-5ubuntu1~16.04) 


If this is not a bug in GCC, but the code is invalid, perhaps the diagnostic could be improved. The diagnostics end in a lambda, saying "use of this in a constant expression", which is confusing, considering that the lambda is not in a context where `this` is valid and `this` does not appear to be used there.
Comment 1 ensadc 2018-08-17 14:54:22 UTC
Removed `#include`:

----
template<typename T>
struct faketuple
{
    template<typename U>
    constexpr faketuple(U&& u) { }

    constexpr faketuple(const faketuple&) = default;
};

namespace ns {
    template <typename A>
    class Foo : private A
    {
    public:
        template <typename FA>
        explicit constexpr Foo(FA&& a)
            : A{static_cast<FA&&>(a)}
        {}
    };

    template <typename A>
    Foo(A)->Foo<A>;

    template <typename T>
    constexpr auto frobnicate(T&& val)
    {
        return [val = static_cast<T&&>(val)] {};
    }

    template <typename A, typename B>
    class Bar
    {
        A a;
        faketuple<B> b;

    public:
        template <typename FA, typename FB>
        explicit constexpr Bar(FA&& a, FB&& b)
            : a{a}
            , b{b}
        {}
    };

    template <typename A, typename B>
    Bar(A, B)->Bar<A, B>;

    constexpr auto Baz = ns::Foo{ns::frobnicate(ns::Bar{[] {}, [](int) {}})};
}

----
But `std::tuple` has a move constructor, unlike `faketuple` :/
Comment 2 Richard Biener 2018-08-22 08:06:54 UTC
clang accepts it.
Comment 3 Drea Pinski 2021-07-29 20:47:39 UTC
Seems fixed in GCC 10+.
Comment 4 Martin Liška 2021-12-08 17:26:34 UTC
Fixed with r11-1677-g0801f419440c14f6.
Comment 5 Drea Pinski 2023-08-12 05:11:19 UTC
(In reply to Martin Liška from comment #4)
> Fixed with r11-1677-g0801f419440c14f6.

No, you missed that you need -std=c++17 to test with the example. That commit just changed the default from -std=gnu++14 to -std=gnu++17  ...
Comment 6 Patrick Palka 2023-12-15 23:33:08 UTC
Fixed with -std=c++17 since r10-3661-g8e007055dd1374 apparently.