Index: libcxx/trunk/docs/UsingLibcxx.rst =================================================================== --- libcxx/trunk/docs/UsingLibcxx.rst +++ libcxx/trunk/docs/UsingLibcxx.rst @@ -226,6 +226,21 @@ replacement scenarios from working, e.g. replacing `operator new` and expecting a non-replaced `operator new[]` to call the replaced `operator new`. +**_LIBCPP_ENABLE_NODISCARD**: + Allow the library to add ``[[nodiscard]]`` attributes to entities not specified + as ``[[nodiscard]]`` by the current language dialect. This includes + backporting applications of ``[[nodiscard]]`` from newer dialects and + additional extended applications at the discretion of the library. All + additional applications of ``[[nodiscard]]`` are disabled by default. + See :ref:`Extended Applications of [[nodiscard]] ` for + more information. + +**_LIBCPP_DISABLE_NODISCARD_EXT**: + This macro prevents the library from applying ``[[nodiscard]]`` to entities + purely as an extension. See :ref:`Extended Applications of [[nodiscard]] ` + for more information. + + C++17 Specific Configuration Macros ----------------------------------- **_LIBCPP_ENABLE_CXX17_REMOVED_FEATURES**: @@ -238,3 +253,58 @@ **_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR**: This macro is used to re-enable `std::auto_ptr` in C++17. + +C++2a Specific Configuration Macros: +------------------------------------ +**_LIBCPP_DISABLE_NODISCARD_AFTER_CXX17**: + This macro can be used to disable diagnostics emitted from functions marked + ``[[nodiscard]]`` in dialects after C++17. See :ref:`Extended Applications of [[nodiscard]] ` + for more information. + + +Libc++ Extensions +================= + +This section documents various extensions provided by libc++, how they're +provided, and any information regarding how to use them. + +.. _nodiscard extension: + +Extended applications of ``[[nodiscard]]`` +------------------------------------------ + +The ``[[nodiscard]]`` attribute is intended to help users find bugs where +function return values are ignored when they shouldn't be. After C++17 the +C++ standard has started to declared such library functions as ``[[nodiscard]]``. +However, this application is limited and applies only to dialects after C++17. +Users who want help diagnosing misuses of STL functions may desire a more +liberal application of ``[[nodiscard]]``. + +For this reason libc++ provides an extension that does just that! The +extension must be enabled by defining ``_LIBCPP_ENABLE_NODISCARD``. The extended +applications of ``[[nodiscard]]`` takes two forms: + +1. Backporting ``[[nodiscard]]`` to entities declared as such by the + standard in newer dialects, but not in the present one. + +2. Extended applications of ``[[nodiscard]]``, at the libraries discretion, + applied to entities never declared as such by the standard. + +Users may also opt-out of additional applications ``[[nodiscard]]`` using +additional macros. + +Applications of the first form, which backport ``[[nodiscard]]`` from a newer +dialect may be disabled using macros specific to the dialect it was added. For +example ``_LIBCPP_DISABLE_NODISCARD_AFTER_CXX17``. + +Applications of the second form, which are pure extensions, may be disabled +by defining ``_LIBCPP_DISABLE_NODISCARD_EXT``. + + +Entities declared with ``_LIBCPP_NODISCARD_EXT`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This section lists all extended applications of ``[[nodiscard]]`` to entities +which no dialect declares as such (See the second form described above). + +* ``get_temporary_buffer`` Index: libcxx/trunk/include/__config =================================================================== --- libcxx/trunk/include/__config +++ libcxx/trunk/include/__config @@ -1049,8 +1049,30 @@ # define _LIBCPP_CONSTEXPR_AFTER_CXX17 #endif -#if __has_cpp_attribute(nodiscard) && _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_DISABLE_NODISCARD_AFTER_CXX17) -# define _LIBCPP_NODISCARD_AFTER_CXX17 [[nodiscard]] +// The _LIBCPP_NODISCARD_ATTRIBUTE should only be used to define other +// NODISCARD macros to the correct attribute. +#if __has_cpp_attribute(nodiscard) || defined(_LIBCPP_COMPILER_MSVC) +# define _LIBCPP_NODISCARD_ATTRIBUTE [[nodiscard]] +#elif defined(_LIBCPP_COMPILER_CLANG) && !defined(_LIBCPP_CXX03_LANG) +# define _LIBCPP_NODISCARD_ATTRIBUTE [[clang::warn_unused_result]] +#else +// We can't use GCC's [[gnu::warn_unused_result]] and +// __attribute__((warn_unused_result)), because GCC does not silence them via +// (void) cast. +# define _LIBCPP_NODISCARD_ATTRIBUTE +#endif + +// _LIBCPP_NODISCARD_EXT may be used to apply [[nodiscard]] to entities not +// specified as such as an extension. +#if defined(_LIBCPP_ENABLE_NODISCARD) && !defined(_LIBCPP_DISABLE_NODISCARD_EXT) +# define _LIBCPP_NODISCARD_EXT _LIBCPP_NODISCARD_ATTRIBUTE +#else +# define _LIBCPP_NODISCARD_EXT +#endif + +#if !defined(_LIBCPP_DISABLE_NODISCARD_AFTER_CXX17) && \ + (_LIBCPP_STD_VER > 17 || defined(_LIBCPP_ENABLE_NODISCARD)) +# define _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_NODISCARD_ATTRIBUTE #else # define _LIBCPP_NODISCARD_AFTER_CXX17 #endif Index: libcxx/trunk/include/memory =================================================================== --- libcxx/trunk/include/memory +++ libcxx/trunk/include/memory @@ -2004,7 +2004,7 @@ }; template -_LIBCPP_NO_CFI +_LIBCPP_NODISCARD_EXT _LIBCPP_NO_CFI pair<_Tp*, ptrdiff_t> get_temporary_buffer(ptrdiff_t __n) _NOEXCEPT { Index: libcxx/trunk/test/libcxx/diagnostics/enable_nodiscard.fail.cpp =================================================================== --- libcxx/trunk/test/libcxx/diagnostics/enable_nodiscard.fail.cpp +++ libcxx/trunk/test/libcxx/diagnostics/enable_nodiscard.fail.cpp @@ -0,0 +1,33 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Test that _LIBCPP_NODISCARD_EXT and _LIBCPP_NODISCARD_AFTER_CXX17 are defined +// to the appropriate warning-generating attribute when _LIBCPP_ENABLE_NODISCARD +// is explicitly provided. + +// UNSUPPORTED: c++98, c++03 + +// GCC 7 is the first version to introduce [[nodiscard]] +// UNSUPPORTED: gcc-4.9, gcc-5, gcc-6 + +// MODULES_DEFINES: _LIBCPP_ENABLE_NODISCARD +#define _LIBCPP_ENABLE_NODISCARD + +#include <__config> + +_LIBCPP_NODISCARD_EXT int foo() { return 42; } +_LIBCPP_NODISCARD_AFTER_CXX17 int bar() { return 42; } + +int main() { + foo(); // expected-error-re {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + bar(); // expected-error-re {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + (void)foo(); // OK. void casts disable the diagnostic. + (void)bar(); +} Index: libcxx/trunk/test/libcxx/diagnostics/enable_nodiscard_disable_after_cxx17.fail.cpp =================================================================== --- libcxx/trunk/test/libcxx/diagnostics/enable_nodiscard_disable_after_cxx17.fail.cpp +++ libcxx/trunk/test/libcxx/diagnostics/enable_nodiscard_disable_after_cxx17.fail.cpp @@ -0,0 +1,33 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// GCC 7 is the first version to introduce [[nodiscard]] +// UNSUPPORTED: gcc-4.9, gcc-5, gcc-6 + +// Test that _LIBCPP_DISABLE_NODISCARD_EXT only disables _LIBCPP_NODISCARD_EXT +// and not _LIBCPP_NODISCARD_AFTER_CXX17. + +// MODULES_DEFINES: _LIBCPP_ENABLE_NODISCARD +// MODULES_DEFINES: _LIBCPP_DISABLE_NODISCARD_AFTER_CXX17 +#define _LIBCPP_ENABLE_NODISCARD +#define _LIBCPP_DISABLE_NODISCARD_AFTER_CXX17 +#include <__config> + + +_LIBCPP_NODISCARD_EXT int foo() { return 42; } +_LIBCPP_NODISCARD_AFTER_CXX17 int bar() { return 42; } + +int main() { + foo(); // expected-error-re {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + bar(); // OK. + (void)foo(); // OK. +} Index: libcxx/trunk/test/libcxx/diagnostics/enable_nodiscard_disable_nodiscard_ext.fail.cpp =================================================================== --- libcxx/trunk/test/libcxx/diagnostics/enable_nodiscard_disable_nodiscard_ext.fail.cpp +++ libcxx/trunk/test/libcxx/diagnostics/enable_nodiscard_disable_nodiscard_ext.fail.cpp @@ -0,0 +1,31 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// GCC 7 is the first version to introduce [[nodiscard]] +// UNSUPPORTED: gcc-4.9, gcc-5, gcc-6 + + +// MODULES_DEFINES: _LIBCPP_ENABLE_NODISCARD +// MODULES_DEFINES: _LIBCPP_DISABLE_NODISCARD_EXT +#define _LIBCPP_ENABLE_NODISCARD +#define _LIBCPP_DISABLE_NODISCARD_EXT +#include <__config> + + +_LIBCPP_NODISCARD_EXT int foo() { return 42; } +_LIBCPP_NODISCARD_AFTER_CXX17 int bar() { return 42; } + +int main() { + bar(); // expected-error-re {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + foo(); // OK. + (void)bar(); // OK. +} Index: libcxx/trunk/test/libcxx/diagnostics/nodiscard.fail.cpp =================================================================== --- libcxx/trunk/test/libcxx/diagnostics/nodiscard.fail.cpp +++ libcxx/trunk/test/libcxx/diagnostics/nodiscard.fail.cpp @@ -1,24 +0,0 @@ -// -*- C++ -*- -//===----------------------------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// Test that _LIBCPP_NODISCARD_AFTER_CXX17 works -// #define _LIBCPP_NODISCARD_AFTER_CXX17 [[nodiscard]] - -// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 -// UNSUPPORTED: clang-3.3, clang-3.4, clang-3.5, clang-3.6, clang-3.7, clang-3.8 - -#include <__config> - -_LIBCPP_NODISCARD_AFTER_CXX17 int foo() { return 6; } - -int main () -{ - foo(); // expected-error {{ignoring return value of function declared with 'nodiscard' attribute}} -} Index: libcxx/trunk/test/libcxx/diagnostics/nodiscard.pass.cpp =================================================================== --- libcxx/trunk/test/libcxx/diagnostics/nodiscard.pass.cpp +++ libcxx/trunk/test/libcxx/diagnostics/nodiscard.pass.cpp @@ -8,18 +8,13 @@ // //===----------------------------------------------------------------------===// -// Test that _LIBCPP_NODISCARD_AFTER_CXX17 works -// #define _LIBCPP_NODISCARD_AFTER_CXX17 [[nodiscard]] +// Test that _LIBCPP_NODISCARD_EXT is not defined to [[nodiscard]] unless +// explicitly enabled by _LIBCPP_ENABLE_NODISCARD -// UNSUPPORTED: c++98, c++03, c++11, c++14 - -// MODULES_DEFINES: _LIBCPP_DISABLE_NODISCARD_AFTER_CXX17 -#define _LIBCPP_DISABLE_NODISCARD_AFTER_CXX17 #include <__config> -_LIBCPP_NODISCARD_AFTER_CXX17 int foo() { return 6; } +_LIBCPP_NODISCARD_EXT int foo() { return 42; } -int main () -{ - foo(); // no error here! +int main() { + foo(); // OK. } Index: libcxx/trunk/test/libcxx/diagnostics/nodiscard_aftercxx17.fail.cpp =================================================================== --- libcxx/trunk/test/libcxx/diagnostics/nodiscard_aftercxx17.fail.cpp +++ libcxx/trunk/test/libcxx/diagnostics/nodiscard_aftercxx17.fail.cpp @@ -0,0 +1,23 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Test that _LIBCPP_NODISCARD_AFTER_CXX17 works +// #define _LIBCPP_NODISCARD_AFTER_CXX17 [[nodiscard]] + +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +#include <__config> + +_LIBCPP_NODISCARD_AFTER_CXX17 int foo() { return 6; } + +int main () +{ + foo(); // expected-error {{ignoring return value of function declared with 'nodiscard' attribute}} +} Index: libcxx/trunk/test/libcxx/diagnostics/nodiscard_aftercxx17.pass.cpp =================================================================== --- libcxx/trunk/test/libcxx/diagnostics/nodiscard_aftercxx17.pass.cpp +++ libcxx/trunk/test/libcxx/diagnostics/nodiscard_aftercxx17.pass.cpp @@ -0,0 +1,23 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Test that _LIBCPP_NODISCARD_AFTER_CXX17 is disabled whenever +// _LIBCPP_DISABLE_NODISCARD_AFTER_CXX17 is defined by the user. + +// MODULES_DEFINES: _LIBCPP_DISABLE_NODISCARD_AFTER_CXX17 +#define _LIBCPP_DISABLE_NODISCARD_AFTER_CXX17 +#include <__config> + +_LIBCPP_NODISCARD_AFTER_CXX17 int foo() { return 6; } + +int main () +{ + foo(); // no error here! +} Index: libcxx/trunk/test/libcxx/diagnostics/nodiscard_extensions.fail.cpp =================================================================== --- libcxx/trunk/test/libcxx/diagnostics/nodiscard_extensions.fail.cpp +++ libcxx/trunk/test/libcxx/diagnostics/nodiscard_extensions.fail.cpp @@ -0,0 +1,32 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// Test that entities declared [[nodiscard]] as at extension by libc++, are +// only actually declared such when _LIBCPP_ENABLE_NODISCARD is specified. + +// All entities to which libc++ applies [[nodiscard]] as an extension should +// be tested here and in nodiscard_extensions.pass.cpp. They should also +// be listed in `UsingLibcxx.rst` in the documentation for the extension. + +// MODULES_DEFINES: _LIBCPP_ENABLE_NODISCARD +#define _LIBCPP_ENABLE_NODISCARD + +#include + +#include "test_macros.h" + +int main() { + { + // expected-error-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + std::get_temporary_buffer(1); + } +} Index: libcxx/trunk/test/libcxx/diagnostics/nodiscard_extensions.pass.cpp =================================================================== --- libcxx/trunk/test/libcxx/diagnostics/nodiscard_extensions.pass.cpp +++ libcxx/trunk/test/libcxx/diagnostics/nodiscard_extensions.pass.cpp @@ -0,0 +1,26 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Test that entities declared [[nodiscard]] as at extension by libc++, are +// only actually declared such when _LIBCPP_ENABLE_NODISCARD is specified. + +// All entities to which libc++ applies [[nodiscard]] as an extension should +// be tested here and in nodiscard_extensions.fail.cpp. They should also +// be listed in `UsingLibcxx.rst` in the documentation for the extension. + +#include + +#include "test_macros.h" + +int main() { + { + std::get_temporary_buffer(1); + } +} Index: libcxx/trunk/utils/libcxx/test/format.py =================================================================== --- libcxx/trunk/utils/libcxx/test/format.py +++ libcxx/trunk/utils/libcxx/test/format.py @@ -250,9 +250,8 @@ # # Therefore, we check if the test was expected to fail because of # nodiscard before enabling it - test_str = "ignoring return value of function declared with " \ - + "'nodiscard' attribute" - if test_str in contents: + test_str_list = ['ignoring return value', 'nodiscard', 'NODISCARD'] + if any(test_str in contents for test_str in test_str_list): test_cxx.flags += ['-Werror=unused-result'] cmd, out, err, rc = test_cxx.compile(source_path, out=os.devnull) expected_rc = 0 if use_verify else 1