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

Reply via email to