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