https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121671
Bug ID: 121671 Summary: Confusing compile error message with std::visit and std::format_string Product: gcc Version: 15.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: chrisi57001 at gmail dot com Target Milestone: --- #include <variant> #include <format> struct Left{}; struct Middle{}; struct Right{}; template<class... Fs> struct Visitor : Fs... { using Fs::operator()...; }; template<class... Args> void logging(std::format_string<Args...>, Args&&... args){} std::variant<Left, Middle, Right> get_variant(int i); int f(int i) { Visitor visitor { [&](Left){ logging("({}}", i); return i; }, [&](Middle){ logging("({})", i+1); return i; }, [&](Right){ logging("({})", i+2); return i; } }; auto variant = get_variant(i/2); return variant.visit(visitor); } As you can hardly see the braces are mismatched in the Left case which generates this error message: <source>: In function 'int f(int)': <source>:42:25: error: call to consteval function 'std::variant<Left, Middle, Right>::visit<>(variant, visitor)' is not a constant expression 42 | return variant.visit(visitor); | ~~~~~~~~~~~~~^~~~~~~~~ In file included from <source>:1: <source>:42:25: in 'constexpr' expansion of 'std::variant<Left, Middle, Right>::visit<>(variant, visitor)' /cefs/b6/b615954805438726f22a60c9_converted_gcc-15.2.0/include/c++/15.2.0/variant:1757:21: in 'constexpr' expansion of 'std::visit<Visitor<f(int)::<lambda(Left)>, f(int)::<lambda(Middle)>, f(int)::<lambda(Right)> >&, variant<Left, Middle, Right>&>((* & std::forward<Visitor<f(int)::<lambda(Left)>, f(int)::<lambda(Middle)>, f(int)::<lambda(Right)> >&>((* & __vis))), (* & * & __self))' /cefs/b6/b615954805438726f22a60c9_converted_gcc-15.2.0/include/c++/15.2.0/variant:1954:34: in 'constexpr' expansion of 'std::__do_visit<__detail::__variant::__deduce_visit_result<int>, Visitor<f(int)::<lambda(Left)>, f(int)::<lambda(Middle)>, f(int)::<lambda(Right)> >&, variant<Left, Middle, Right>&>((* & std::forward<Visitor<f(int)::<lambda(Left)>, f(int)::<lambda(Middle)>, f(int)::<lambda(Right)> >&>((* & __visitor))), (* & __variants#0))' /cefs/b6/b615954805438726f22a60c9_converted_gcc-15.2.0/include/c++/15.2.0/variant:1889:26: in 'constexpr' expansion of '(& __v0)->std::variant<Left, Middle, Right>::index()' /cefs/b6/b615954805438726f22a60c9_converted_gcc-15.2.0/include/c++/15.2.0/variant:1681:24: error: the value of 'variant' is not usable in a constant expression 1681 | return this->_M_index; | ~~~~~~^~~~~~~~ <source>:41:10: note: 'variant' was not declared 'constexpr' 41 | auto variant = get_variant(i/2); | ^~~~~~~ /cefs/b6/b615954805438726f22a60c9_converted_gcc-15.2.0/include/c++/15.2.0/variant:1757:28: note: 'constexpr decltype(auto) std::variant<_Types>::visit(this _Self&&, _Visitor&&) [with int <anonymous> = 0; _Self = std::variant<Left, Middle, Right>&; _Visitor = Visitor<f(int)::<lambda(Left)>, f(int)::<lambda(Middle)>, f(int)::<lambda(Right)> >&; _Types = {Left, Middle, Right}]' was promoted to an immediate function because its body contains an immediate-escalating expression 'std::visit<Visitor<f(int)::<lambda(Left)>, f(int)::<lambda(Middle)>, f(int)::<lambda(Right)> >&, variant<Left, Middle, Right>&>(__vis, __self)' 1757 | return std::visit(std::forward<_Visitor>(__vis), (_Var)__self); | ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ASM generation compiler returned: 1 <source>: In function 'int f(int)': <source>:42:25: error: call to consteval function 'std::variant<Left, Middle, Right>::visit<>(variant, visitor)' is not a constant expression 42 | return variant.visit(visitor); | ~~~~~~~~~~~~~^~~~~~~~~ In file included from <source>:1: <source>:42:25: in 'constexpr' expansion of 'std::variant<Left, Middle, Right>::visit<>(variant, visitor)' /cefs/b6/b615954805438726f22a60c9_converted_gcc-15.2.0/include/c++/15.2.0/variant:1757:21: in 'constexpr' expansion of 'std::visit<Visitor<f(int)::<lambda(Left)>, f(int)::<lambda(Middle)>, f(int)::<lambda(Right)> >&, variant<Left, Middle, Right>&>((* & std::forward<Visitor<f(int)::<lambda(Left)>, f(int)::<lambda(Middle)>, f(int)::<lambda(Right)> >&>((* & __vis))), (* & * & __self))' /cefs/b6/b615954805438726f22a60c9_converted_gcc-15.2.0/include/c++/15.2.0/variant:1954:34: in 'constexpr' expansion of 'std::__do_visit<__detail::__variant::__deduce_visit_result<int>, Visitor<f(int)::<lambda(Left)>, f(int)::<lambda(Middle)>, f(int)::<lambda(Right)> >&, variant<Left, Middle, Right>&>((* & std::forward<Visitor<f(int)::<lambda(Left)>, f(int)::<lambda(Middle)>, f(int)::<lambda(Right)> >&>((* & __visitor))), (* & __variants#0))' /cefs/b6/b615954805438726f22a60c9_converted_gcc-15.2.0/include/c++/15.2.0/variant:1889:26: in 'constexpr' expansion of '(& __v0)->std::variant<Left, Middle, Right>::index()' /cefs/b6/b615954805438726f22a60c9_converted_gcc-15.2.0/include/c++/15.2.0/variant:1681:24: error: the value of 'variant' is not usable in a constant expression 1681 | return this->_M_index; | ~~~~~~^~~~~~~~ <source>:41:10: note: 'variant' was not declared 'constexpr' 41 | auto variant = get_variant(i/2); | ^~~~~~~ /cefs/b6/b615954805438726f22a60c9_converted_gcc-15.2.0/include/c++/15.2.0/variant:1757:28: note: 'constexpr decltype(auto) std::variant<_Types>::visit(this _Self&&, _Visitor&&) [with int <anonymous> = 0; _Self = std::variant<Left, Middle, Right>&; _Visitor = Visitor<f(int)::<lambda(Left)>, f(int)::<lambda(Middle)>, f(int)::<lambda(Right)> >&; _Types = {Left, Middle, Right}]' was promoted to an immediate function because its body contains an immediate-escalating expression 'std::visit<Visitor<f(int)::<lambda(Left)>, f(int)::<lambda(Middle)>, f(int)::<lambda(Right)> >&, variant<Left, Middle, Right>&>(__vis, __self)' 1757 | return std::visit(std::forward<_Visitor>(__vis), (_Var)__self); | ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Execution build compiler returned: 1 Initially that was very confusing since none of this should be constexpr but I was able to track the error message down to my logging because that was the only component using a consteval function. (Godbolt: https://godbolt.org/z/W5T8a5sfa) The library already has nicer error messages for unbalanced braces but somehow they didn't trigger here like they do in this sample: #include <format> template<class... Args> void logging(std::format_string<Args...>, Args&&... args) {} struct S { void operator()() { logging("Hello}"); // Useful error here } };