Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 9 May 2025 22:50:35 GMT
From:      Lexi Winter <ivy@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 7e0c5e0128c4 - main - sys/cdefs.h: add __nodiscard annotation
Message-ID:  <202505092250.549MoZsx028151@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202505092250.549MoZsx028151>