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(); }