[libc++][memory] Applied [[nodiscard]] to more functions (#172131)
`[[nodiscard]]` should be applied to functions where discarding the return value is most likely a correctness issue. - https://libcxx.llvm.org/CodingGuidelines.html - https://wg21.link/allocator.traits - https://wg21.link/specialized.addressof - https://wg21.link/ptr.align - https://timsong-cpp.github.io/cppwp/n4659/depr.default.allocator - https://timsong-cpp.github.io/cppwp/n4659/depr.storage.iterator Towards #172124
This commit is contained in:
parent
6c2c0b9da2
commit
e593dbc184
@ -19,7 +19,8 @@
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_NO_CFI _LIBCPP_HIDE_FROM_ABI _Tp* addressof(_Tp& __x) _NOEXCEPT {
|
||||
[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_NO_CFI _LIBCPP_HIDE_FROM_ABI _Tp*
|
||||
addressof(_Tp& __x) _NOEXCEPT {
|
||||
return __builtin_addressof(__x);
|
||||
}
|
||||
|
||||
@ -27,24 +28,25 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_NO_CFI _LIBCPP_HIDE_FROM_ABI _Tp* a
|
||||
// Objective-C++ Automatic Reference Counting uses qualified pointers
|
||||
// that require special addressof() signatures.
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_HIDE_FROM_ABI __strong _Tp* addressof(__strong _Tp& __x) _NOEXCEPT {
|
||||
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __strong _Tp* addressof(__strong _Tp& __x) _NOEXCEPT {
|
||||
return &__x;
|
||||
}
|
||||
|
||||
# if __has_feature(objc_arc_weak)
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_HIDE_FROM_ABI __weak _Tp* addressof(__weak _Tp& __x) _NOEXCEPT {
|
||||
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __weak _Tp* addressof(__weak _Tp& __x) _NOEXCEPT {
|
||||
return &__x;
|
||||
}
|
||||
# endif
|
||||
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_HIDE_FROM_ABI __autoreleasing _Tp* addressof(__autoreleasing _Tp& __x) _NOEXCEPT {
|
||||
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __autoreleasing _Tp* addressof(__autoreleasing _Tp& __x) _NOEXCEPT {
|
||||
return &__x;
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_HIDE_FROM_ABI __unsafe_unretained _Tp* addressof(__unsafe_unretained _Tp& __x) _NOEXCEPT {
|
||||
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __unsafe_unretained _Tp*
|
||||
addressof(__unsafe_unretained _Tp& __x) _NOEXCEPT {
|
||||
return &__x;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -120,10 +120,11 @@ public:
|
||||
typedef allocator<_Up> other;
|
||||
};
|
||||
|
||||
_LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI pointer address(reference __x) const _NOEXCEPT {
|
||||
[[__nodiscard__]] _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI pointer address(reference __x) const _NOEXCEPT {
|
||||
return std::addressof(__x);
|
||||
}
|
||||
_LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI const_pointer address(const_reference __x) const _NOEXCEPT {
|
||||
[[__nodiscard__]] _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI const_pointer
|
||||
address(const_reference __x) const _NOEXCEPT {
|
||||
return std::addressof(__x);
|
||||
}
|
||||
|
||||
@ -131,7 +132,7 @@ public:
|
||||
return allocate(__n);
|
||||
}
|
||||
|
||||
_LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT {
|
||||
[[__nodiscard__]] _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT {
|
||||
return size_type(~0) / sizeof(_Tp);
|
||||
}
|
||||
|
||||
|
||||
@ -314,23 +314,25 @@ struct allocator_traits {
|
||||
}
|
||||
|
||||
template <class _Ap = _Alloc, __enable_if_t<__has_max_size_v<const _Ap>, int> = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static size_type max_size(const allocator_type& __a) _NOEXCEPT {
|
||||
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static size_type
|
||||
max_size(const allocator_type& __a) _NOEXCEPT {
|
||||
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
|
||||
return __a.max_size();
|
||||
_LIBCPP_SUPPRESS_DEPRECATED_POP
|
||||
}
|
||||
template <class _Ap = _Alloc, __enable_if_t<!__has_max_size_v<const _Ap>, int> = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static size_type max_size(const allocator_type&) _NOEXCEPT {
|
||||
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static size_type
|
||||
max_size(const allocator_type&) _NOEXCEPT {
|
||||
return numeric_limits<size_type>::max() / sizeof(value_type);
|
||||
}
|
||||
|
||||
template <class _Ap = _Alloc, __enable_if_t<__has_select_on_container_copy_construction_v<const _Ap>, int> = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static allocator_type
|
||||
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static allocator_type
|
||||
select_on_container_copy_construction(const allocator_type& __a) {
|
||||
return __a.select_on_container_copy_construction();
|
||||
}
|
||||
template <class _Ap = _Alloc, __enable_if_t<!__has_select_on_container_copy_construction_v<const _Ap>, int> = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static allocator_type
|
||||
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static allocator_type
|
||||
select_on_container_copy_construction(const allocator_type& __a) {
|
||||
return __a;
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
|
||||
#if _LIBCPP_STD_VER >= 26
|
||||
|
||||
template <size_t _Alignment, class _Tp>
|
||||
_LIBCPP_HIDE_FROM_ABI bool is_sufficiently_aligned(_Tp* __ptr) {
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_sufficiently_aligned(_Tp* __ptr) {
|
||||
return reinterpret_cast<uintptr_t>(__ptr) % _Alignment == 0;
|
||||
}
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@ public:
|
||||
typedef void reference;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI explicit raw_storage_iterator(_OutputIterator __x) : __x_(__x) {}
|
||||
_LIBCPP_HIDE_FROM_ABI raw_storage_iterator& operator*() { return *this; }
|
||||
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI raw_storage_iterator& operator*() { return *this; }
|
||||
_LIBCPP_HIDE_FROM_ABI raw_storage_iterator& operator=(const _Tp& __element) {
|
||||
::new ((void*)std::addressof(*__x_)) _Tp(__element);
|
||||
return *this;
|
||||
@ -67,7 +67,7 @@ public:
|
||||
return __t;
|
||||
}
|
||||
# if _LIBCPP_STD_VER >= 14
|
||||
_LIBCPP_HIDE_FROM_ABI _OutputIterator base() const { return __x_; }
|
||||
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _OutputIterator base() const { return __x_; }
|
||||
# endif
|
||||
};
|
||||
|
||||
|
||||
@ -6,37 +6,122 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03
|
||||
// <memory>
|
||||
|
||||
// check that <memory> functions are marked [[nodiscard]]
|
||||
// Check that functions are marked [[nodiscard]]
|
||||
|
||||
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_CXX20_REMOVED_RAW_STORAGE_ITERATOR
|
||||
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_CXX20_REMOVED_TEMPORARY_BUFFER
|
||||
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
// clang-format off
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
void test() {
|
||||
std::get_temporary_buffer<int>(0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
}
|
||||
int i = 0;
|
||||
|
||||
void test_allocator_traits() {
|
||||
std::allocator<int> allocator;
|
||||
std::allocator_traits<std::allocator<int>> allocator_traits;
|
||||
allocator_traits.allocate(allocator, 1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
allocator_traits.allocate(allocator, 1, nullptr); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
}
|
||||
|
||||
void test_allocator() {
|
||||
std::allocator<int> allocator;
|
||||
allocator.allocate(1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
#if TEST_STD_VER <= 17
|
||||
allocator.allocate(1, nullptr); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
{
|
||||
std::addressof(i); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::get_temporary_buffer<int>(0);
|
||||
#if _LIBCPP_STD_VER >= 26
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::is_sufficiently_aligned<2>(&i);
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
struct Alloc {
|
||||
using value_type = int;
|
||||
|
||||
value_type* allocate(std::size_t) { return nullptr; }
|
||||
} allocator;
|
||||
using AllocTraits = std::allocator_traits<Alloc>;
|
||||
|
||||
struct HintedAlloc {
|
||||
using value_type = int;
|
||||
using size_type = std::size_t;
|
||||
using const_void_pointer = const void*;
|
||||
|
||||
value_type* allocate(size_type) { return nullptr; }
|
||||
value_type* allocate(size_type, const_void_pointer) { return nullptr; }
|
||||
} hintedAllocator;
|
||||
using HintedAllocTraits = std::allocator_traits<HintedAlloc>;
|
||||
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
AllocTraits::allocate(allocator, 1);
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
HintedAllocTraits::allocate(hintedAllocator, 1, nullptr);
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
AllocTraits::allocate(allocator, 1, nullptr);
|
||||
|
||||
#if TEST_STD_VER >= 23
|
||||
allocator.allocate_at_least(1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
AllocTraits::allocate_at_least(allocator, 1);
|
||||
#endif
|
||||
|
||||
struct SizedAlloc {
|
||||
using value_type = int;
|
||||
using size_type = std::size_t;
|
||||
|
||||
value_type* allocate(std::size_t) { return nullptr; }
|
||||
value_type* allocate(std::size_t, const void*) { return nullptr; }
|
||||
|
||||
size_type max_size() const { return 0; }
|
||||
} sizedAllocator;
|
||||
using SizedAllocTraits = std::allocator_traits<SizedAlloc>;
|
||||
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
SizedAllocTraits::max_size(sizedAllocator);
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
AllocTraits::max_size(allocator);
|
||||
|
||||
struct SelectAlloc {
|
||||
using value_type = int;
|
||||
using const_void_pointer = const void*;
|
||||
|
||||
value_type* allocate(std::size_t) { return nullptr; }
|
||||
value_type* allocate(std::size_t, const void*) { return nullptr; }
|
||||
|
||||
SelectAlloc select_on_container_copy_construction() const { return SelectAlloc(); };
|
||||
} selectAllocator;
|
||||
using SelectAllocTraits = std::allocator_traits<SelectAlloc>;
|
||||
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
SelectAllocTraits::select_on_container_copy_construction(selectAllocator);
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
AllocTraits::select_on_container_copy_construction(allocator);
|
||||
}
|
||||
|
||||
{
|
||||
std::allocator<int> allocator;
|
||||
|
||||
allocator.allocate(1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
|
||||
#if TEST_STD_VER >= 23
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
allocator.allocate_at_least(1);
|
||||
#endif
|
||||
|
||||
#if TEST_STD_VER <= 17
|
||||
const int ci = 0;
|
||||
|
||||
allocator.address(i); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
allocator.address(ci); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
allocator.allocate(1, nullptr);
|
||||
allocator.max_size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if TEST_STD_VER >= 14
|
||||
{
|
||||
std::raw_storage_iterator<int*, int> it{nullptr};
|
||||
|
||||
*it; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
it.base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// <memory>
|
||||
|
||||
// template <class Alloc>
|
||||
// struct allocator_traits
|
||||
// {
|
||||
// static constexpr pointer allocate(allocator_type& a, size_type n);
|
||||
// ...
|
||||
// };
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
|
||||
template <class T>
|
||||
struct A {
|
||||
typedef T value_type;
|
||||
value_type* allocate(std::size_t n);
|
||||
value_type* allocate(std::size_t n, const void* p);
|
||||
};
|
||||
|
||||
void f() {
|
||||
A<int> a;
|
||||
std::allocator_traits<A<int> >::allocate(a, 10); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::allocator_traits<A<int> >::allocate(a, 10, nullptr); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user