From 9bd8085c98fc9943def745c0ca4c87ac6a35d9de Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Thu, 8 Oct 2020 21:45:52 -0700 Subject: [PATCH 1/2] Add _CONTAINER_DEBUG_LEVEL checks for optional When `_CONTAINER_DEBUG_LEVEL` is `1` (which is implied by `_ITERATOR_DEBUG_LEVEL != 0`) `optional::operator*` and `optional::operator->` verify the precondition that the `optional` is not empty. Drive-by: Add a default constructor to `death_test_executive` so we need not construct with a do-nothing function when there are no "normal" tests. --- stl/inc/optional | 18 ++++++ tests/std/include/test_death.hpp | 9 +-- tests/std/test.lst | 1 + .../std/tests/P0220R1_optional_death/env.lst | 4 ++ .../std/tests/P0220R1_optional_death/test.cpp | 59 +++++++++++++++++++ .../tests/P0660R10_stop_token_death/test.cpp | 2 +- .../P0896R4_common_iterator_death/test.cpp | 2 +- .../P0896R4_counted_iterator_death/test.cpp | 2 +- .../tests/P0896R4_views_filter_death/test.cpp | 2 +- .../P0896R4_views_transform_death/test.cpp | 2 +- 10 files changed, 92 insertions(+), 9 deletions(-) create mode 100644 tests/std/tests/P0220R1_optional_death/env.lst create mode 100644 tests/std/tests/P0220R1_optional_death/test.cpp diff --git a/stl/inc/optional b/stl/inc/optional index e852cda7b38..04e36c0c10b 100644 --- a/stl/inc/optional +++ b/stl/inc/optional @@ -338,22 +338,40 @@ public: // observers [optional.object.observe] _NODISCARD constexpr const _Ty* operator->() const { +#if _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(this->_Has_value, "Cannot access value of empty optional"); +#endif // _CONTAINER_DEBUG_LEVEL > 0 return _STD addressof(this->_Value); } _NODISCARD constexpr _Ty* operator->() { +#if _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(this->_Has_value, "Cannot access value of empty optional"); +#endif // _CONTAINER_DEBUG_LEVEL > 0 return _STD addressof(this->_Value); } _NODISCARD constexpr const _Ty& operator*() const& { +#if _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(this->_Has_value, "Cannot access value of empty optional"); +#endif // _CONTAINER_DEBUG_LEVEL > 0 return this->_Value; } _NODISCARD constexpr _Ty& operator*() & { +#if _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(this->_Has_value, "Cannot access value of empty optional"); +#endif // _CONTAINER_DEBUG_LEVEL > 0 return this->_Value; } _NODISCARD constexpr _Ty&& operator*() && { +#if _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(this->_Has_value, "Cannot access value of empty optional"); +#endif // _CONTAINER_DEBUG_LEVEL > 0 return _STD move(this->_Value); } _NODISCARD constexpr const _Ty&& operator*() const&& { +#if _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(this->_Has_value, "Cannot access value of empty optional"); +#endif // _CONTAINER_DEBUG_LEVEL > 0 return _STD move(this->_Value); } diff --git a/tests/std/include/test_death.hpp b/tests/std/include/test_death.hpp index 801f813bcb1..943b0f28a02 100644 --- a/tests/std/include/test_death.hpp +++ b/tests/std/include/test_death.hpp @@ -12,7 +12,6 @@ #include namespace std_testing { - constexpr int internal_failure = 103; using normal_function_t = void (*)(); using death_function_t = void (*)(); @@ -23,7 +22,6 @@ namespace std_testing { abort(); } - class death_test_executive { const normal_function_t run_normal_tests; std::vector death_tests; @@ -98,10 +96,11 @@ namespace std_testing { } public: + death_test_executive() : run_normal_tests(nullptr) {} + explicit death_test_executive(const normal_function_t normal_tests_function) : run_normal_tests(normal_tests_function) {} - template void add_death_tests(const death_function_t (&tests)[TestsCount]) { death_tests.insert(death_tests.end(), tests, std::end(tests)); @@ -111,7 +110,9 @@ namespace std_testing { if (argc == 1) { // first pass, run normal tests and sub-process loop printf("running normal tests..."); - run_normal_tests(); + if (run_normal_tests != nullptr) { + run_normal_tests(); + } puts(" passed!"); ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); diff --git a/tests/std/test.lst b/tests/std/test.lst index 3855902a344..ce4aff5bb8d 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -215,6 +215,7 @@ tests\P0202R3_constexpr_algorithm_and_exchange tests\P0218R1_filesystem tests\P0220R1_any tests\P0220R1_optional +tests\P0220R1_optional_death tests\P0220R1_polymorphic_memory_resources tests\P0220R1_sample tests\P0220R1_searchers diff --git a/tests/std/tests/P0220R1_optional_death/env.lst b/tests/std/tests/P0220R1_optional_death/env.lst new file mode 100644 index 00000000000..46a3592c2e6 --- /dev/null +++ b/tests/std/tests/P0220R1_optional_death/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_17_winsdk_matrix.lst diff --git a/tests/std/tests/P0220R1_optional_death/test.cpp b/tests/std/tests/P0220R1_optional_death/test.cpp new file mode 100644 index 00000000000..9dad2622719 --- /dev/null +++ b/tests/std/tests/P0220R1_optional_death/test.cpp @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#define _CONTAINER_DEBUG_LEVEL 1 + +#include + +#include + +using namespace std; + +struct S { + int value; +}; + +void test_nullopt_operator_arrow() { + optional o; + (void) o->value; +} + +void test_nullopt_operator_arrow_const() { + const optional o; + (void) o->value; +} + +void test_nullopt_operator_star_lvalue() { + optional o; + (void) *o; +} + +void test_nullopt_operator_star_const_lvalue() { + const optional o; + (void) *o; +} + +void test_nullopt_operator_star_rvalue() { + optional o; + (void) *move(o); +} + +void test_nullopt_operator_star_const_rvalue() { + const optional o; + (void) *move(o); +} + +int main(int argc, char* argv[]) { + std_testing::death_test_executive exec; + + exec.add_death_tests({ + test_nullopt_operator_arrow, + test_nullopt_operator_arrow_const, + test_nullopt_operator_star_lvalue, + test_nullopt_operator_star_const_lvalue, + test_nullopt_operator_star_rvalue, + test_nullopt_operator_star_const_rvalue, + }); + + return exec.run(argc, argv); +} diff --git a/tests/std/tests/P0660R10_stop_token_death/test.cpp b/tests/std/tests/P0660R10_stop_token_death/test.cpp index e9075218b7a..ef74ee52326 100644 --- a/tests/std/tests/P0660R10_stop_token_death/test.cpp +++ b/tests/std/tests/P0660R10_stop_token_death/test.cpp @@ -36,7 +36,7 @@ void test_case_throw_during_request_stop() { } int main(int argc, char* argv[]) { - std_testing::death_test_executive exec([] {}); + std_testing::death_test_executive exec; exec.add_death_tests({ test_case_throw_during_request_stop, diff --git a/tests/std/tests/P0896R4_common_iterator_death/test.cpp b/tests/std/tests/P0896R4_common_iterator_death/test.cpp index 131b1fdf6cf..9409bcfb9a2 100644 --- a/tests/std/tests/P0896R4_common_iterator_death/test.cpp +++ b/tests/std/tests/P0896R4_common_iterator_death/test.cpp @@ -156,7 +156,7 @@ void test_case_iter_swap_sentinel_right_valueless() { } int main(int argc, char* argv[]) { - std_testing::death_test_executive exec([] {}); + std_testing::death_test_executive exec; #if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ diff --git a/tests/std/tests/P0896R4_counted_iterator_death/test.cpp b/tests/std/tests/P0896R4_counted_iterator_death/test.cpp index 3c0157fddef..523490ee19f 100644 --- a/tests/std/tests/P0896R4_counted_iterator_death/test.cpp +++ b/tests/std/tests/P0896R4_counted_iterator_death/test.cpp @@ -206,7 +206,7 @@ void test_case_operator_spaceship_incompatible_value_initialized() { } int main(int argc, char* argv[]) { - std_testing::death_test_executive exec([] {}); + std_testing::death_test_executive exec; #if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ diff --git a/tests/std/tests/P0896R4_views_filter_death/test.cpp b/tests/std/tests/P0896R4_views_filter_death/test.cpp index 01c4017ca98..d784bedca19 100644 --- a/tests/std/tests/P0896R4_views_filter_death/test.cpp +++ b/tests/std/tests/P0896R4_views_filter_death/test.cpp @@ -131,7 +131,7 @@ void test_iter_swap_value_initialized_iterator_right() { } int main(int argc, char* argv[]) { - std_testing::death_test_executive exec([] {}); + std_testing::death_test_executive exec; #if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ diff --git a/tests/std/tests/P0896R4_views_transform_death/test.cpp b/tests/std/tests/P0896R4_views_transform_death/test.cpp index 5dfa72da1b3..edb51eb5a62 100644 --- a/tests/std/tests/P0896R4_views_transform_death/test.cpp +++ b/tests/std/tests/P0896R4_views_transform_death/test.cpp @@ -334,7 +334,7 @@ void test_flipped_sentinel_difference_value_initialized() { } int main(int argc, char* argv[]) { - std_testing::death_test_executive exec([] {}); + std_testing::death_test_executive exec; #if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ From 922d16262174b9e01253393f5b0f6775cdb0904a Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Fri, 9 Oct 2020 20:35:46 -0700 Subject: [PATCH 2/2] Review comments Co-authored-by: Stephan T. Lavavej --- tests/std/tests/P0220R1_optional_death/test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/std/tests/P0220R1_optional_death/test.cpp b/tests/std/tests/P0220R1_optional_death/test.cpp index 9dad2622719..bdc284f0028 100644 --- a/tests/std/tests/P0220R1_optional_death/test.cpp +++ b/tests/std/tests/P0220R1_optional_death/test.cpp @@ -4,6 +4,7 @@ #define _CONTAINER_DEBUG_LEVEL 1 #include +#include #include