diff --git a/CMakeLists.txt b/CMakeLists.txt index 13643b0..e0b2751 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -185,6 +185,12 @@ if (ARGS_BUILD_UNITTESTS) args_configure_test(${target_name}) add_test(NAME ${test_name} COMMAND ${target_name}) endforeach () + + # ARGS_NOEXCEPT exists so the header can be used where exceptions are off, + # so build this one with them off to keep that working. + if (NOT MSVC) + target_compile_options(argstest-no_exceptions PRIVATE -fno-exceptions) + endif () endif() add_library(taywee::args ALIAS args) diff --git a/args.hxx b/args.hxx index ed1e2c1..a2d6cf7 100644 --- a/args.hxx +++ b/args.hxx @@ -398,13 +398,7 @@ namespace args if (can_reserve && total > 0) { - try - { - res.reserve(total); - } - catch (...) { - // Fall back to default allocation - } + res.reserve(total); } bool first = true; diff --git a/meson.build b/meson.build index c909762..235d764 100644 --- a/meson.build +++ b/meson.build @@ -103,4 +103,11 @@ endforeach test('multiple_inclusion', executable('argstest-multiple_inclusion', sources: ['test/multiple_inclusion.cxx', 'test/multiple_inclusion.aux.cxx'], dependencies: args_dep)) + +# ARGS_NOEXCEPT exists so the header can be used where exceptions are off, so +# build this one with them off to keep that working. +test('no_exceptions', executable('argstest-no_exceptions', + sources: 'test/no_exceptions.cxx', + cpp_args: meson.get_compiler('cpp').get_supported_arguments('-fno-exceptions'), + dependencies: args_dep)) endif diff --git a/test/no_exceptions.cxx b/test/no_exceptions.cxx new file mode 100644 index 0000000..13312f2 --- /dev/null +++ b/test/no_exceptions.cxx @@ -0,0 +1,34 @@ +/* Copyright (c) Taylor Richberger + * This code is released under the license described in the LICENSE file + * + * Compiled with the compiler's exception support switched off (see + * CMakeLists.txt and meson.build), so anything in args.hxx that needs + * exceptions outside of the ARGS_NOEXCEPT guards breaks this test at compile + * time. + */ + +#define ARGS_NOEXCEPT +#include "test_common.hxx" + +#include + +#include "test_helpers.hxx" + +int main() +{ + args::ArgumentParser p("parser"); + args::CompletionFlag c(p, {"completion"}); + args::Flag f(p, "foo", "description", {'f', "foo"}); + args::MapFlag m(p, "map", "description", {'m', "map"}, {{"alpha", 1}, {"beta", 2}}); + + p.ParseArgs(std::vector{"--map", "beta", "-f"}); + test::require(p.GetError() == args::Error::None); + test::require(args::get(m) == 2); + + // Completion replies are assembled by args::detail::Join. + p.ParseArgs(std::vector{"--completion", "bash", "2", "test", "--map", ""}); + test::require(p.GetError() == args::Error::Completion); + test::require(args::get(c) == "alpha\nbeta"); + + return 0; +} diff --git a/test/test_helpers.hxx b/test/test_helpers.hxx index af760e3..af77045 100644 --- a/test/test_helpers.hxx +++ b/test/test_helpers.hxx @@ -38,6 +38,10 @@ inline void require_false(bool cond) } } +// The throwing helpers are unusable in a translation unit built without +// exception support, and merely parsing them is an error there. +#ifdef __cpp_exceptions + template void require_nothrow(F &&f) { @@ -101,6 +105,8 @@ void require_throws_with(F &&f, const std::string &expected) fail("require_throws_with: nothing thrown"); } +#endif + template void require_contains(const ContainerT& container, const TargetT& target) {