Skip to content

Construction of an empty class "value" in a lexy production fails to compile on MSVC #224

@totalgee

Description

@totalgee

This is a strange, because it seems to compile and work fine on GCC and clang, but on MSVC (17.12.3) it fails to compile. Even on MSVC, it does work as expected, when you use lexy "normally", at runtime. The compilation error only happens when trying to use static_assert to check productions in constexpr at compile time. And even so, the static assert testing works as expected for the WithData class, just not the NoData class (that gets lexy::constructed without arguments). It seems to be related to the attempt to construct the class using lazy_init, but there are no args to forward.

Here is an example -- as I say, these "productions" build and parse fine at runtime, but when I use static_assert to check it at compile time as shown at the bottom of the code example, it fails to compile. It also fails if I just have the test() function return a bool true, so I don't think it's to do with the string_view...

namespace test {
    struct NoData {
        constexpr std::string_view test() const {
            return "NoData";
        }
    };

    struct WithData {
        constexpr auto test() const {
            return str;
        }
        std::string_view str;
    };

    static constexpr auto ident = dsl::identifier(dsl::ascii::alpha, dsl::ascii::alpha_digit_underscore);
    static constexpr auto ws1 = dsl::while_one(dsl::ascii::space);
    struct argument {
        struct invalid {
            static constexpr auto name = "invalid argument character";
        };
        static constexpr auto rule = ident;
        static constexpr auto value = lexy::as_string<std::string_view>;
    };

    struct cmd_NoData {
        static constexpr auto rule = LEXY_KEYWORD("NoData", ident) + dsl::eof;
        static constexpr auto value = lexy::construct<NoData>;
    };

    struct cmd_WithData {
        static constexpr auto rule = LEXY_KEYWORD("WithData", ident) >> ws1
            + dsl::p<argument> + dsl::eof;
        static constexpr auto value = lexy::construct<WithData>;
    };

    static_assert([] {
        constexpr auto result = lexy::parse<cmd_WithData>(lexy::zstring_input("WithData hello"), lexy::noop);
        return result.has_value() && result.value().test() == "hello";
    }());
    static_assert([] {
        constexpr auto result = lexy::parse<cmd_NoData>(lexy::zstring_input("NoData"), lexy::noop);  // <-- this is line 89
        return result.has_value() && result.value().test() == "NoData";
    }());
} // namespace test

The compile errors start with:

C:\Users\...\src\test_Parser.cpp(89): error C2131: expression did not evaluate to a constant
  C:\Users\...\out\build\x64-debug\vcpkg_installed\x64-windows\include\lexy/_detail/lazy_init.hpp(110): note: failure was caused by a read of an uninitialized symbol
  C:\Users\...\out\build\x64-debug\vcpkg_installed\x64-windows\include\lexy/_detail/lazy_init.hpp(110): note: see usage of 'lexy::_detail::_lazy_init_storage_trivial<T>::_value'
          with
          [
              T=test::NoData
          ]
  C:\Users\...\src\test_Parser.inl(89): note: the call stack of the evaluation (the oldest call first) is
  C:\Users\...\src\test_Parser.inl(89): note: while evaluating function 'lexy::parse_result<lexy::do_action::value_type,ErrorCallback> lexy::parse<test::cmd_NoData,lexy::string_input<lexy::default_encoding>,lexy::_noop>(const Input &,const ErrorCallback &)'
          with
          [
              ErrorCallback=lexy::_noop,
              Input=lexy::string_input<lexy::default_encoding>
          ]
  C:\Users\...\out\build\x64-debug\vcpkg_installed\x64-windows\include\lexy/action/parse.hpp(173): note: while evaluating function 'lexy::parse_result<lexy::do_action::value_type,ErrorCallback> lexy::parse_action<void,lexy::string_input<lexy::default_encoding>,ErrorCallback>::operator ()<test::cmd_NoData>(Production,const Input &) const'
          with
          [
              ErrorCallback=lexy::_noop,
              Production=test::cmd_NoData,
              Input=lexy::string_input<lexy::default_encoding>
          ]

P.S. Even stranger, the IntelliSense "squiggles" that show (red underlines) indicating an error are not present. If you modify the string input so it's invalid, you do get those static_assert red squiggly line appearing. As soon as you change it to "NoData", which should parse, the squiggles go away, so this "pre-compiler" seems to think it's error-free. But then when you actually build the file/project, you get the above errors... Again, if I comment out this static_assert and just use the lexy parser at runtime, everything seems to work fine, and I get the expected return value from the test() method on NoData.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions