cppfront
cppfront copied to clipboard
[BUG] Varargs breaks with non-PODs
Title: Varargs breaks with non-PODs.
Description:
With Clang, an error stopped me from having a broken program: https://cpp1.godbolt.org/z/xW8qjhnfP. With MSVC, this is actually just a warning. With GCC, there's no warning at all.
Minimal reproducer (https://cpp2.godbolt.org/z/oPfvj3cEz):
#include <ranges>
using namespace std::views;
using std::string;
main: () = {
(base_types := 0.iota(), //
base_targs := :std::vector = ("".string().repeat(1), ("<(42)$>").repeat(1 << 16)))
for zip(base_types, base_targs) do (b) ("this: (b.get<0>())$(b.get<1>())$ = ();").clear();
}
Commands:
cppfront main.cpp2
clang++18 -std=c++23 -stdlib=libc++ -lc++abi -pedantic-errors -Wall -Wextra -Wconversion -Werror=unused-result -I . main.cpp
Expected result:
This apparently broken function not to exist: https://github.com/hsutter/cppfront/blob/8a9346033ad5ec4608ebd8292539e0718f9d991b/include/cpp2util.h#L872
Actual result and error:
Cpp2 lowered to Cpp1:
//=== Cpp2 type declarations ====================================================
#include "cpp2util.h"
//=== Cpp2 type definitions and function declarations ===========================
#include <ranges>
using namespace std::views;
using std::string;
auto main() -> int;
//=== Cpp2 function definitions =================================================
auto main() -> int{
{
auto const& base_types = CPP2_UFCS_0(iota, 0);
auto const& base_targs = std::vector{CPP2_UFCS(repeat, CPP2_UFCS_0(string, ""), 1), CPP2_UFCS(repeat, ("<" + cpp2::to_string(42) + ">"), 1 << 16)};
//
for ( auto const& b : zip(base_types, base_targs) ) CPP2_UFCS_0(clear, ("this: " + cpp2::to_string(CPP2_UFCS_TEMPLATE_0(get, (<0>), b)) + cpp2::to_string(CPP2_UFCS_TEMPLATE_0(get, (<1>), b)) + " = ();"));
}
}
main.cpp2:7:159: error: cannot pass object of non-trivial type 'const std::ranges::repeat_view<std::string, int>' through variadic function; call will abort at runtime [-Wnon-pod-varargs]
7 | for ( auto const& b : zip(base_types, base_targs) ) CPP2_UFCS_0(clear, ("this: " + cpp2::to_string(CPP2_UFCS_TEMPLATE_0(get, (<0>), b)) + cpp2::to_string(CPP2_UFCS_TEMPLATE_0(get, (<1>), b)) + " = ();"));
| ^
raw.githubusercontent.com/hsutter/cppfront/main/include/cpp2util.h:810:56: note: expanded from macro 'CPP2_UFCS_TEMPLATE_0'
810 | #define CPP2_UFCS_TEMPLATE_0(FUNCNAME,TEMPARGS,PARAM1) \
| ^
1 error generated.
It seems like GCC executes just fine: https://cpp1.godbolt.org/z/jMz8YGnE8.
This simpler reproducer illustrates the problem.
Minimal reproducer (https://cpp2.godbolt.org/z/9cPPe6Tb9):
main: (args) = {
_ = "(args)$";
}
Commands:
cppfront main.cpp2
clang++18 -std=c++23 -stdlib=libc++ -lc++abi -pedantic-errors -Wall -Wextra -Wconversion -Werror=unused-result -I . main.cpp
Cpp2 lowered to Cpp1:
//=== Cpp2 type declarations ====================================================
#include "cpp2util.h"
#line 1 "/app/example.cpp2"
//=== Cpp2 type definitions and function declarations ===========================
#line 1 "/app/example.cpp2"
auto main(int const argc_, char** argv_) -> int;
//=== Cpp2 function definitions =================================================
#line 1 "/app/example.cpp2"
auto main(int const argc_, char** argv_) -> int{
auto const args = cpp2::make_args(argc_, argv_);
#line 2 "/app/example.cpp2"
static_cast<void>(cpp2::to_string(args));
}
main.cpp2:2:37: error: cannot pass object of non-trivial type 'const args_t' through variadic function; call will abort at runtime [-Wnon-pod-varargs]
2 | static_cast<void>(cpp2::to_string(args));
| ^
1 error generated.
I think this means that it's falling back to the "this didn't work, need to make a function for this" case, which really should be a build error, not just a runtime failure.
inline auto to_string(...) -> std::string
{
return "(customize me - no cpp2::to_string overload exists for this type)";
}
LLVM 18 works fine if I -D__cpp_lib_format.
Otherwise, for some reason, the varargs overload is chosen.
See https://cpp2.godbolt.org/z/zeqTrhbd1:
main: () = {
std::cout << "(0:>23)$\n";
std::cout << "(:std::vector=(0,1,2);:>23)$";
}
Thanks. Do you have a suggested fix? For example, do you prefer removing that fallback overload, changing it to (auto&&...), or something else?
I would be in favor of making it a compile error, especially if we can get some decent error messages out of the error.