[Bug c++/85149] New: False branch of if constexpr instantiated in generic lambda

barry.revzin at gmail dot com gcc-bugzilla@gcc.gnu.org
Sat Mar 31 21:54:00 GMT 2018


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

            Bug ID: 85149
           Summary: False branch of if constexpr instantiated in generic
                    lambda
           Product: gcc
           Version: 8.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

On latest trunk (8.0.1), the following compiles. But with -DBUG it doesn't:

template <typename T> struct is_void { static constexpr bool value = false; };
template <> struct is_void<void> { static constexpr bool value = true; };

template<typename S, typename T>
constexpr decltype(auto) pipeline(S source, T target)
{
    return [=](auto... args)
    {
        if constexpr(false 
                     #ifdef BUG
                     && is_void<decltype(source(args...))>::value
                     #endif
                    )
        {
            source(args...);
            return target();
        } else {
            return target(source(args...));
        }
    };
}

int main() {
    pipeline([]{ return 10; },
             [](int val){ return val * 10; });
}

With -DBUG, the error is:

prog.cc: In instantiation of 'constexpr decltype(auto) pipeline(S, T) [with S =
main()::<lambda()>; T = main()::<lambda(int)>]':
prog.cc:25:45:   required from here
prog.cc:16:26: error: no match for call to '(const main()::<lambda(int)>) ()'
             return target();
                    ~~~~~~^~
prog.cc:16:26: note: candidate: 'int (*)(int)' <conversion>
prog.cc:16:26: note:   candidate expects 2 arguments, 1 provided
prog.cc:25:24: note: candidate: 'main()::<lambda(int)>'
              [](int val){ return val * 10; });
                        ^
prog.cc:25:24: note:   candidate expects 1 argument, 0 provided

-----------------

Wrapping source and target into an aggregate instead gets you an ICE on gcc 7.3
(https://godbolt.org/g/WvzuCs):

template <typename T> struct is_void { static constexpr bool value = false; };
template <> struct is_void<void> { static constexpr bool value = true; };

template <typename S, typename T>
struct pair {
    S first;
    T second;
};
template <typename S, typename T> pair(S, T) -> pair<S,T>;

template<typename S, typename T>
constexpr decltype(auto) pipeline(S&& source, T&& target)
{
    return [callables = pair{source, target}](auto... args)
    {
        auto& [source, target] = callables;
        using source_return = decltype(source(args...));

        if constexpr(false && is_void<source_return>::value)
        {
            source(args...);
            return target();
        }
    };
}

void foo()
{
    auto s = []{ return 42; };
    auto t = [](int){};
    auto p = pipeline(s, t);
    p();
}


More information about the Gcc-bugs mailing list