Skip to content
143 changes: 59 additions & 84 deletions stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -549,89 +549,65 @@
#define _FALLTHROUGH
#endif

// _HAS_NODISCARD (in vcruntime.h) controls:
// [[nodiscard]] attributes on STL functions
// vcruntime.h defines _NODISCARD to [[nodiscard]]
#define _NODISCARD_CTOR [[nodiscard]]

// TRANSITION, This should go to vcruntime.h
#ifndef __has_cpp_attribute
#define _NODISCARD_MSG(_Msg)
#elif __has_cpp_attribute(nodiscard) >= 201907L
#define _NODISCARD_MSG(_Msg) [[nodiscard(_Msg)]]
#elif __has_cpp_attribute(nodiscard) >= 201603L
#define _NODISCARD_MSG(_Msg) [[nodiscard]]
#else
#define _NODISCARD_MSG(_Msg)
#endif
#define _NODISCARD_REMOVE_ALG \
[[nodiscard("The 'remove' and 'remove_if' algorithms return the iterator past the last element " \
"that should be kept. You need to call container.erase(result, container.end()) afterwards. " \
"In C++20, 'std::erase' and 'std::erase_if' are simpler replacements for these two steps.")]]

#ifndef __has_cpp_attribute
#define _NODISCARD_CTOR
#define _NODISCARD_CTOR_MSG(_Msg)
#elif __has_cpp_attribute(nodiscard) >= 201907L
#define _NODISCARD_CTOR _NODISCARD
#define _NODISCARD_CTOR_MSG(_Msg) _NODISCARD_MSG(_Msg)
#else // ^^^ __has_cpp_attribute(nodiscard) >= 201907L / __has_cpp_attribute(nodiscard) < 201907L vvv
#define _NODISCARD_CTOR
#define _NODISCARD_CTOR_MSG(_Msg)
#endif // ^^^ defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard) < 201907L ^^^

#define _NODISCARD_REMOVE_ALG \
_NODISCARD_MSG("The 'remove' and 'remove_if' algorithms return the iterator past the last element " \
"that should be kept. You need to call container.erase(result, container.end()) afterwards. " \
"In C++20, 'std::erase' and 'std::erase_if' are simpler replacements for these two steps.")

#define _NODISCARD_UNIQUE_ALG \
_NODISCARD_MSG("The 'unique' algorithm returns the iterator past the last element that should be kept. " \
"You need to call container.erase(result, container.end()) afterwards.")
#define _NODISCARD_UNIQUE_ALG \
[[nodiscard("The 'unique' algorithm returns the iterator past the last element that should be kept. " \
"You need to call container.erase(result, container.end()) afterwards.")]]

#define _NODISCARD_EMPTY_MEMBER \
_NODISCARD_MSG( \
[[nodiscard( \
"This member function returns a bool indicating whether the collection is empty and has no other effects. " \
"It is not useful to call this member function and discard the return value. " \
"Use the 'clear()' member function if you want to erase all elements.")
"Use the 'clear()' member function if you want to erase all elements.")]]

#define _NODISCARD_EMPTY_ARRAY_MEMBER \
_NODISCARD_MSG( \
"This member function returns a bool indicating whether the array is empty and has no other effects. " \
"It is not useful to call this member function and discard the return value. " \
"There's no way to clear an array as its size is fixed.")
#define _NODISCARD_EMPTY_ARRAY_MEMBER \
[[nodiscard("This member function returns a bool indicating whether the array is empty and has no other effects. " \
"It is not useful to call this member function and discard the return value. " \
"There's no way to clear an array as its size is fixed.")]]

#define _NODISCARD_EMPTY_MEMBER_NO_CLEAR \
_NODISCARD_MSG( \
[[nodiscard( \
"This member function returns a bool indicating whether the collection is empty and has no other effects. " \
"It is not useful to call this member function and discard the return value. " \
"This collection can be cleared by assigning an empty value to it.")
"This collection can be cleared by assigning an empty value to it.")]]

#define _NODISCARD_EMPTY_NON_MEMBER \
_NODISCARD_MSG("This function returns a bool indicating whether the collection is empty and " \
"has no other effects. It is not useful to call this function and discard the return value.")
#define _NODISCARD_EMPTY_NON_MEMBER \
[[nodiscard("This function returns a bool indicating whether the collection is empty and " \
"has no other effects. It is not useful to call this function and discard the return value.")]]

#define _NODISCARD_BARRIER_TOKEN \
_NODISCARD_MSG("The token from 'arrive()' should not be discarded; it should be passed to 'wait()'.")
[[nodiscard("The token from 'arrive()' should not be discarded; it should be passed to 'wait()'.")]]

#define _NODISCARD_TRY_WAIT \
_NODISCARD_MSG( \
"This member function returns the state of the synchronization object and does not do anything else; " \
"it is not useful to call this member function and discard the return value.")
#define _NODISCARD_TRY_WAIT \
[[nodiscard("This member function returns the state of the synchronization object and does not do anything else; " \
"it is not useful to call this member function and discard the return value.")]]

#define _NODISCARD_TRY_CHANGE_STATE \
_NODISCARD_MSG("This function returns whether the operation succeeded in modifying object state. " \
"It is dangerous to ignore the return value.")
#define _NODISCARD_TRY_CHANGE_STATE \
[[nodiscard("This function returns whether the operation succeeded in modifying object state. " \
"It is dangerous to ignore the return value.")]]

#define _NODISCARD_SMART_PTR_ALLOC \
_NODISCARD_MSG("This function constructs an object wrapped by a smart pointer and has no other effects; " \
"it is not useful to call this function and discard the return value.")
#define _NODISCARD_SMART_PTR_ALLOC \
[[nodiscard("This function constructs an object wrapped by a smart pointer and has no other effects; " \
"it is not useful to call this function and discard the return value.")]]

#define _NODISCARD_RAW_PTR_ALLOC \
_NODISCARD_MSG("This function allocates memory and returns a raw pointer. " \
"Discarding the return value will cause a memory leak.")
#define _NODISCARD_RAW_PTR_ALLOC \
[[nodiscard("This function allocates memory and returns a raw pointer. " \
"Discarding the return value will cause a memory leak.")]]

#define _NODISCARD_ASSUME_ALIGNED \
_NODISCARD_MSG("'std::assume_aligned' has a potential effect on the return value (not on the passed argument). " \
"It is not useful to call 'std::assume_aligned' and discard the return value.")
#define _NODISCARD_ASSUME_ALIGNED \
[[nodiscard("'std::assume_aligned' has a potential effect on the return value (not on the passed argument). " \
"It is not useful to call 'std::assume_aligned' and discard the return value.")]]

#define _NODISCARD_LAUNDER \
_NODISCARD_MSG("'std::launder' has a potential effect on the return value (not on the passed argument). " \
"It is not useful to call 'std::launder' and discard the return value.")
#define _NODISCARD_LAUNDER \
[[nodiscard("'std::launder' has a potential effect on the return value (not on the passed argument). " \
"It is not useful to call 'std::launder' and discard the return value.")]]

#ifdef _SILENCE_NODISCARD_LOCK_WARNINGS

Expand All @@ -640,35 +616,34 @@

#else // ^^^ defined(_SILENCE_NODISCARD_LOCK_WARNINGS) / !defined(_SILENCE_NODISCARD_LOCK_WARNINGS) vvv

#define _NODISCARD_LOCK \
_NODISCARD_MSG("A lock should be stored in a variable to protect the scope. If you're intentionally constructing " \
"a temporary to protect the rest of the current expression using the comma operator, you can cast " \
"the temporary to void or define _SILENCE_NODISCARD_LOCK_WARNINGS to suppress this warning.")
#define _NODISCARD_LOCK \
[[nodiscard("A lock should be stored in a variable to protect the scope. If you're intentionally constructing " \
"a temporary to protect the rest of the current expression using the comma operator, you can cast " \
"the temporary to void or define _SILENCE_NODISCARD_LOCK_WARNINGS to suppress this warning.")]]

#define _NODISCARD_CTOR_LOCK \
_NODISCARD_CTOR_MSG( \
"A lock should be stored in a variable to protect the scope. If you're intentionally constructing " \
"a temporary to protect the rest of the current expression using the comma operator, you can cast " \
"the temporary to void or define _SILENCE_NODISCARD_LOCK_WARNINGS to suppress this warning.")
#define _NODISCARD_CTOR_LOCK \
[[nodiscard("A lock should be stored in a variable to protect the scope. If you're intentionally constructing " \
"a temporary to protect the rest of the current expression using the comma operator, you can cast " \
"the temporary to void or define _SILENCE_NODISCARD_LOCK_WARNINGS to suppress this warning.")]]

#endif // ^^^ !defined(_SILENCE_NODISCARD_LOCK_WARNINGS) ^^^

#define _NODISCARD_CTOR_THREAD \
_NODISCARD_CTOR_MSG("This temporary 'std::thread' is not joined or detached, " \
"so 'std::terminate' will be called at the end of the statement.")
#define _NODISCARD_CTOR_THREAD \
[[nodiscard("This temporary 'std::thread' is not joined or detached, " \
"so 'std::terminate' will be called at the end of the statement.")]]

#define _NODISCARD_CTOR_JTHREAD \
_NODISCARD_CTOR_MSG("This temporary 'std::jthread' is implicitly joined at the end of the statement. " \
"If this is intentional, you can add '.join()' to suppress this warning. " \
"Otherwise, this 'std::jthread' should be stored in a variable.")
#define _NODISCARD_CTOR_JTHREAD \
[[nodiscard("This temporary 'std::jthread' is implicitly joined at the end of the statement. " \
"If this is intentional, you can add '.join()' to suppress this warning. " \
"Otherwise, this 'std::jthread' should be stored in a variable.")]]

#define _NODISCARD_ASYNC \
_NODISCARD_MSG("The result of 'std::async' should be stored in a variable. If the return value is discarded, " \
"the temporary 'std::future' is destroyed, waiting for an async result or evaluating " \
"a deferred result, thus defeating the purpose of 'std::async'.")
#define _NODISCARD_ASYNC \
[[nodiscard("The result of 'std::async' should be stored in a variable. If the return value is discarded, " \
"the temporary 'std::future' is destroyed, waiting for an async result or evaluating " \
"a deferred result, thus defeating the purpose of 'std::async'.")]]

#define _NODISCARD_GET_FUTURE \
_NODISCARD_MSG("Since 'get_future' may be called only once, discarding the result is likely a mistake.")
[[nodiscard("Since 'get_future' may be called only once, discarding the result is likely a mistake.")]]

#pragma push_macro("msvc")
#pragma push_macro("known_semantics")
Expand Down