As requested in <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425#c41>, this is a proof-of-concept patch to change -Wunused-result to not warn about return values explicitly discarded by casting to void, and add -Wunused-result=strict for the current behavior (warn even on void casts). The core behavior change is based on an earlier patch at <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509#c10>; it appears to do the correct thing based on the tests added by the patch, but it also breaks a number of other attribute- and analyzer-related tests, so some fine-tuning is probably needed (and I don't have the GCC internals knowledge to know where to start).
I haven't touched [[nodiscard]] behavior, since GCC already ignores explicit discards in that case; for consistency's sake, it might make sense to also warn for explicitly discarded [[nodiscard]] values with -Wunused-result=strict. Please CC me on any replies, as I am not subscribed to the list. --Andrew Church https://achurch.org/ diff -urN gcc-12.2.0-orig/gcc/c-family/c.opt gcc-12.2.0/gcc/c-family/c.opt --- gcc-12.2.0-orig/gcc/c-family/c.opt 2022-08-19 17:09:52 +0900 +++ gcc-12.2.0/gcc/c-family/c.opt 2023-04-23 03:39:58 +0900 @@ -1361,6 +1361,10 @@ C ObjC C++ ObjC++ Var(warn_unused_result) Init(1) Warning Warn if a caller of a function, marked with attribute warn_unused_result, does not use its return value. +Wunused-result=strict +C ObjC C++ ObjC++ RejectNegative Var(warn_unused_result,2) Init(1) Warning +Warn if a caller of a function, marked with attribute warn_unused_result, does not use its return value. + Wunused-variable C ObjC C++ ObjC++ LangEnabledBy(C ObjC C++ ObjC++,Wunused) ; documented in common.opt diff -urN gcc-12.2.0-orig/gcc/doc/invoke.texi gcc-12.2.0/gcc/doc/invoke.texi --- gcc-12.2.0-orig/gcc/doc/invoke.texi 2022-08-19 17:09:52 +0900 +++ gcc-12.2.0/gcc/doc/invoke.texi 2023-04-23 03:32:36 +0900 @@ -406,7 +406,7 @@ -Wunused-const-variable -Wunused-const-variable=@var{n} @gol -Wunused-function -Wunused-label -Wunused-local-typedefs @gol -Wunused-macros @gol --Wunused-parameter -Wno-unused-result @gol +-Wunused-parameter -Wunused-result -Wunused-result=strict @gol -Wunused-value -Wunused-variable @gol -Wno-varargs -Wvariadic-macros @gol -Wvector-operation-performance @gol @@ -7037,12 +7037,20 @@ To suppress this warning use the @code{unused} attribute (@pxref{Variable Attributes}). -@item -Wno-unused-result +@item -Wunused-result @opindex Wunused-result @opindex Wno-unused-result -Do not warn if a caller of a function marked with attribute +Warn if a caller of a function marked with attribute @code{warn_unused_result} (@pxref{Function Attributes}) does not use -its return value. The default is @option{-Wunused-result}. +its return value, unless the return value is explicitly discarded with a +cast to @code{void}. This warning is enabled by default. + +@item -Wunused-result=strict +@opindex Wunused-result=strict +Warn if a caller of a function marked with attribute +@code{warn_unused_result} (@pxref{Function Attributes}) does not use +its return value, even if the return value is explicitly discarded with +a cast to @code{void}. @item -Wunused-variable @opindex Wunused-variable diff -urN gcc-12.2.0-orig/gcc/gimplify.cc gcc-12.2.0/gcc/gimplify.cc --- gcc-12.2.0-orig/gcc/gimplify.cc 2022-08-19 17:09:52 +0900 +++ gcc-12.2.0/gcc/gimplify.cc 2023-04-23 03:34:02 +0900 @@ -15183,10 +15183,18 @@ || fallback == fb_none) { /* Just strip a conversion to void (or in void context) and - try again. */ - *expr_p = TREE_OPERAND (*expr_p, 0); - ret = GS_OK; - break; + try again. But if this is a function call cast to void + and strict unused-result warnings are not enabled, + preserve the cast so that do_warn_unused_result() knows + not to emit a warning. */ + if (!(warn_unused_result == 1 + && TREE_CODE (TREE_OPERAND (*expr_p, 0)) == CALL_EXPR + && VOID_TYPE_P (TREE_TYPE (*expr_p)))) + { + *expr_p = TREE_OPERAND (*expr_p, 0); + ret = GS_OK; + break; + } } ret = gimplify_conversion (expr_p); diff -urN gcc-12.2.0-orig/gcc/testsuite/c-c++-common/attr-warn-unused-result.c gcc-12.2.0/gcc/testsuite/c-c++-common/attr-warn-unused-result.c --- gcc-12.2.0-orig/gcc/testsuite/c-c++-common/attr-warn-unused-result.c 2022-08-19 17:09:53 +0900 +++ gcc-12.2.0/gcc/testsuite/c-c++-common/attr-warn-unused-result.c 2023-04-22 20:01:42 +0900 @@ -1,6 +1,6 @@ /* warn_unused_result attribute tests. */ /* { dg-do compile } */ -/* { dg-options "-O -ftrack-macro-expansion=0" } */ +/* { dg-options "-O -ftrack-macro-expansion=0 -Wunused-result=strict" } */ #define WUR __attribute__((warn_unused_result)) #define WURAI __attribute__((warn_unused_result, always_inline)) inline diff -urN gcc-12.2.0-orig/gcc/testsuite/gcc.dg/Wunused-result-2.c gcc-12.2.0/gcc/testsuite/gcc.dg/Wunused-result-2.c --- gcc-12.2.0-orig/gcc/testsuite/gcc.dg/Wunused-result-2.c 1970-01-01 09:00:00 +0900 +++ gcc-12.2.0/gcc/testsuite/gcc.dg/Wunused-result-2.c 2023-04-23 04:17:01 +0900 @@ -0,0 +1,11 @@ +/* Test for -Wno-unused-result inhibiting all unused-result warnings. + { dg-do compile } + { dg-options "-Wno-unused-result" } */ + +__attribute__ ((warn_unused_result)) int fwur (void); + +void wur (void) +{ + fwur (); // no warning + (void) fwur (); // no warning +} diff -urN gcc-12.2.0-orig/gcc/testsuite/gcc.dg/Wunused-result-3.c gcc-12.2.0/gcc/testsuite/gcc.dg/Wunused-result-3.c --- gcc-12.2.0-orig/gcc/testsuite/gcc.dg/Wunused-result-3.c 1970-01-01 09:00:00 +0900 +++ gcc-12.2.0/gcc/testsuite/gcc.dg/Wunused-result-3.c 2023-04-23 03:29:19 +0900 @@ -0,0 +1,12 @@ +/* Test for -Wunused-result inhibiting unused-result warnings when the + value is explicitly cast to void. + { dg-do compile } + { dg-options "-Wunused-result" } */ + +__attribute__ ((warn_unused_result)) int fwur (void); + +void wur (void) +{ + fwur (); // { dg-warning "\\\[-Wunused-result" } + (void) fwur (); // no warning +} diff -urN gcc-12.2.0-orig/gcc/testsuite/gcc.dg/Wunused-result-4.c gcc-12.2.0/gcc/testsuite/gcc.dg/Wunused-result-4.c --- gcc-12.2.0-orig/gcc/testsuite/gcc.dg/Wunused-result-4.c 1970-01-01 09:00:00 +0900 +++ gcc-12.2.0/gcc/testsuite/gcc.dg/Wunused-result-4.c 2023-04-23 03:29:35 +0900 @@ -0,0 +1,12 @@ +/* Test for -Wunused-result=strict emitting unused-result warnings even + when the value is explicitly cast to void. + { dg-do compile } + { dg-options "-Wunused-result=strict" } */ + +__attribute__ ((warn_unused_result)) int fwur (void); + +void wur (void) +{ + fwur (); // { dg-warning "\\\[-Wunused-result" } + (void) fwur (); // { dg-warning "\\\[-Wunused-result" } +}