git: 7e0c5e0128c4 - main - sys/cdefs.h: add __nodiscard annotation
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 09 May 2025 22:50:35 UTC
The branch main has been updated by ivy:
URL: https://cgit.FreeBSD.org/src/commit/?id=7e0c5e0128c43bbae78190911aead8e1d9475ba5
commit 7e0c5e0128c43bbae78190911aead8e1d9475ba5
Author: Lexi Winter <ivy@FreeBSD.org>
AuthorDate: 2025-05-09 21:28:14 +0000
Commit: Lexi Winter <ivy@FreeBSD.org>
CommitDate: 2025-05-09 22:50:23 +0000
sys/cdefs.h: add __nodiscard annotation
__nodiscard adds the [[nodiscard]] attribute to a function, type or
constructor in C or C++, causing a value so marked to issue a compiler
warning if it is discarded (i.e., not used or assigned) other than by
casting it to void.
this replaces the existing __result_use_or_ignore_check, which has a
similar purpose but different semantics. since __nodiscard provides
more functionality (at least in GCC) and __result_use_or_ignore_check
only had a single user, remove __result_use_or_ignore_check.
[[nodiscard]] has been supported in C++ since C++17, but only in C since
C23; however, both LLVM and GCC implement it even in older language
versions, so it should always be available with a relatively modern
compiler.
for Clang, [[nodiscard]] in C is only available since LLVM 17, but we
can fall back to __attribute__((__warn_unused_result__)) which has the
same semantics and provides support back to (at least) LLVM 11.
GCC supports [[nodiscard]] in both C and C++ since at least GCC 11.
for GCC, we can't provide a fallback as the semantics of its
warn_unused_result are different, but since __result_use_or_ignore_check
isn't defined for GCC anyway, we don't lose anything here.
MFC after: 2 weeks
Reviewed by: des, emaste
Approved by: des (mentor)
Differential Revision: https://reviews.freebsd.org/D50217
---
share/man/man9/cdefs.9 | 19 +++++++++++++++----
sys/sys/cdefs.h | 50 ++++++++++++++++++++++++++++++++++++++------------
sys/sys/systm.h | 14 +++++++-------
3 files changed, 60 insertions(+), 23 deletions(-)
diff --git a/share/man/man9/cdefs.9 b/share/man/man9/cdefs.9
index 4efce132d393..397ddb0891bb 100644
--- a/share/man/man9/cdefs.9
+++ b/share/man/man9/cdefs.9
@@ -3,7 +3,7 @@
.\"
.\" SPDX-License-Identifier: BSD-2-Clause
.\"
-.Dd January 6, 2025
+.Dd May 9, 2025
.Dt CDEFS 9
.Os
.Sh NAME
@@ -118,9 +118,20 @@ family of functions.
.It Sy __fastcall Ta Use the
.Dq fastcall
ABI to call and name mangle this function.
-.It Sy __result_use_check Ta Warn if function caller does not use it's return value
-.It Sy __result_use_or_ignore_check Ta Warn if function caller does not use it's return value.
-Allows the value to be explicitly ignored with a (void) cast.
+.It Sy __result_use_check Ta Warn if function caller does not use its return value
+.It Sy __nodiscard Ta Equivalent to the standard
+.Dq [[nodiscard]]
+attribute.
+If applied to a function, warn if function caller does not use its
+return value.
+The warning may be silenced using a cast to
+.Vt void ,
+or in C++, using an assignment to
+.Va std::ignore .
+If applied to a struct, C++ class or enum, this applies to all functions
+returning values of that type.
+If applied to a C++ constructor, this applies to creating instances of
+the class using that constructor.
.It Sy __returns_twice Ta Returns multiple times, like
.Xr fork 2
.It Sy __unreachable Ta This code is not reachable at runtime
diff --git a/sys/sys/cdefs.h b/sys/sys/cdefs.h
index c46be9f35842..e79cf2972f3f 100644
--- a/sys/sys/cdefs.h
+++ b/sys/sys/cdefs.h
@@ -253,18 +253,6 @@
#define __noinline __attribute__ ((__noinline__))
#define __fastcall __attribute__((__fastcall__))
#define __result_use_check __attribute__((__warn_unused_result__))
-#ifdef __clang__
-/*
- * clang and gcc have different semantics for __warn_unused_result__: the latter
- * does not permit the use of a void cast to suppress the warning. Use
- * __result_use_or_ignore_check in places where a void cast is acceptable.
- * This can be implemented by [[nodiscard]] from C23.
- */
-#define __result_use_or_ignore_check __result_use_check
-#else
-#define __result_use_or_ignore_check
-#endif /* !__clang__ */
-
#define __returns_twice __attribute__((__returns_twice__))
#define __unreachable() __builtin_unreachable()
@@ -295,6 +283,44 @@
#define __noexcept_if(__c)
#endif
+/*
+ * nodiscard attribute added in C++17 and C23, but supported by both LLVM and
+ * GCC in earlier language versions, so we use __has_c{,pp}_attribute to test
+ * for it.
+ *
+ * __nodiscard may be used on a function:
+ * __nodiscard int f();
+ *
+ * or on a struct, union or enum:
+ * struct __nodiscard S{};
+ * struct S f();
+ *
+ * or in C++, on an object constructor.
+ */
+
+#if defined(__cplusplus) && defined(__has_cpp_attribute)
+#if __has_cpp_attribute(nodiscard)
+#define __nodiscard [[nodiscard]]
+#endif
+#elif defined(__STDC_VERSION__) && defined(__has_c_attribute)
+#if __has_c_attribute(__nodiscard__)
+#define __nodiscard [[__nodiscard__]]
+#endif
+#endif
+
+#ifndef __nodiscard
+/*
+ * LLVM 16 and earlier don't support [[nodiscard]] in C, but they do support
+ * __warn_unused_result__ with the same semantics, so fall back to that.
+ * We can't do this for GCC because the semantics are different.
+ */
+#ifdef __clang__
+#define __nodiscard __attribute__((__warn_unused_result__))
+#else
+#define __nodiscard
+#endif
+#endif
+
/*
* We use `__restrict' as a way to define the `restrict' type qualifier
* without disturbing older software that is unaware of C99 keywords.
diff --git a/sys/sys/systm.h b/sys/sys/systm.h
index f542a9a86018..7cc02c77bea4 100644
--- a/sys/sys/systm.h
+++ b/sys/sys/systm.h
@@ -309,9 +309,9 @@ int __result_use_check copyin(const void * __restrict udaddr,
void * _Nonnull __restrict kaddr, size_t len);
int __result_use_check copyin_nofault(const void * __restrict udaddr,
void * _Nonnull __restrict kaddr, size_t len);
-int __result_use_or_ignore_check copyout(const void * _Nonnull __restrict kaddr,
+__nodiscard int copyout(const void * _Nonnull __restrict kaddr,
void * __restrict udaddr, size_t len);
-int __result_use_or_ignore_check copyout_nofault(
+__nodiscard int copyout_nofault(
const void * _Nonnull __restrict kaddr, void * __restrict udaddr,
size_t len);
@@ -334,11 +334,11 @@ int64_t fuword64(volatile const void *base);
int __result_use_check fueword(volatile const void *base, long *val);
int __result_use_check fueword32(volatile const void *base, int32_t *val);
int __result_use_check fueword64(volatile const void *base, int64_t *val);
-int __result_use_or_ignore_check subyte(volatile void *base, int byte);
-int __result_use_or_ignore_check suword(volatile void *base, long word);
-int __result_use_or_ignore_check suword16(volatile void *base, int word);
-int __result_use_or_ignore_check suword32(volatile void *base, int32_t word);
-int __result_use_or_ignore_check suword64(volatile void *base, int64_t word);
+__nodiscard int subyte(volatile void *base, int byte);
+__nodiscard int suword(volatile void *base, long word);
+__nodiscard int suword16(volatile void *base, int word);
+__nodiscard int suword32(volatile void *base, int32_t word);
+__nodiscard int suword64(volatile void *base, int64_t word);
uint32_t casuword32(volatile uint32_t *base, uint32_t oldval, uint32_t newval);
u_long casuword(volatile u_long *p, u_long oldval, u_long newval);
int casueword32(volatile uint32_t *base, uint32_t oldval, uint32_t *oldvalp,