[PATCH] c, c++: Fix unused result for empty types [PR82134]
Hi, This fixes PR c/82134 which concerns gcc emitting an incorrect unused result diagnostic for empty types. This diagnostic is emitted from tree-cfg.cc because of a couple code paths which attempt to avoid copying empty types, resulting in GIMPLE that isn't using the returned value of a call. To fix this I've added suppress_warning in three locations and a corresponding check in do_warn_unused_result. Cheers, Jeremy PR c/82134 gcc/cp/ChangeLog: * call.cc (build_call_a): Add suppress_warning * cp-gimplify.cc (cp_gimplify_expr): Add suppress_warning gcc/ChangeLog: * gimplify.cc (gimplify_modify_expr): Add suppress_warning * tree-cfg.cc (do_warn_unused_result): Check warning_suppressed_p gcc/testsuite/ChangeLog: * c-c++-common/attr-warn-unused-result-2.c: New test. Signed-off-by: Jeremy Rifkin --- gcc/cp/call.cc| 1 + gcc/cp/cp-gimplify.cc | 1 + gcc/gimplify.cc | 1 + .../c-c++-common/attr-warn-unused-result-2.c | 15 +++ gcc/tree-cfg.cc | 2 ++ 5 files changed, 20 insertions(+) create mode 100644 gcc/testsuite/c-c++-common/attr-warn-unused-result-2.c diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 2c3ef3dfc35..a70fc13c6a4 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -412,6 +412,7 @@ build_call_a (tree function, int n, tree *argarray) /* We're disconnecting the initializer from its target, don't create a temporary. */ arg = TARGET_EXPR_INITIAL (arg); +suppress_warning (arg, OPT_Wunused_result); tree t = build0 (EMPTY_CLASS_EXPR, TREE_TYPE (arg)); arg = build2 (COMPOUND_EXPR, TREE_TYPE (t), arg, t); CALL_EXPR_ARG (function, i) = arg; diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index 0fcfa16d2c5..2a21e960994 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -690,6 +690,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) && (REFERENCE_CLASS_P (op1) || DECL_P (op1))) op1 = build_fold_addr_expr (op1); +suppress_warning (op1, OPT_Wunused_result); gimplify_and_add (op1, pre_p); } gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index 9f9ff92d064..fa9890e7cea 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -7305,6 +7305,7 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, && !(TREE_ADDRESSABLE (TREE_TYPE (*from_p)) && TREE_CODE (*from_p) == CALL_EXPR)) { + suppress_warning (*from_p, OPT_Wunused_result); gimplify_stmt (from_p, pre_p); gimplify_stmt (to_p, pre_p); *expr_p = NULL_TREE; diff --git a/gcc/testsuite/c-c++-common/attr-warn-unused-result-2.c b/gcc/testsuite/c-c++-common/attr-warn-unused-result-2.c new file mode 100644 index 000..09be1a933c9 --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-warn-unused-result-2.c @@ -0,0 +1,15 @@ +// PR c/82134 +/* { dg-do compile } */ + +struct S {}; + +__attribute__((warn_unused_result)) struct S foo(); + +void use_s(struct S); + +void +test (void) +{ + struct S s = foo(); /* { dg-bogus "ignoring return value of" } */ + use_s(foo()); /* { dg-bogus "ignoring return value of" } */ +} diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc index fad308e7f7b..5cd72ed1b3e 100644 --- a/gcc/tree-cfg.cc +++ b/gcc/tree-cfg.cc @@ -9961,6 +9961,8 @@ do_warn_unused_result (gimple_seq seq) break; if (gimple_call_internal_p (g)) break; + if (warning_suppressed_p (g, OPT_Wunused_result)) +break; /* This is a naked call, as opposed to a GIMPLE_CALL with an LHS. All calls whose value is ignored should be -- 2.43.0
Re: [PATCH] c, c++: Fix unused result for empty types [PR82134]
Hi Jason, Thank you so much for taking a look! > This is OK, but I wonder about making do_warn_unused_result ignore empty > types in general; if there's no data in the type, what does it matter if > we ignore the empty box? I'm not strongly opinionated and I think there are good arguments both ways. Looking at other implementations, I see clang and msvc both warn on warn_unused_result/nodiscard for empty types. I think the primary time this would really matter is generic programming, if I'm working with `template [[nodiscard]] T foo();` I would probably want a warning if I discarded the result, even if it's being instantiated with T = empty type. Cheers, Jeremy On Tue, Jul 8, 2025 at 11:23 AM Jason Merrill wrote: > > On 6/9/25 9:00 PM, Jeremy Rifkin wrote: > > Hi, > > This fixes PR c/82134 which concerns gcc emitting an incorrect unused > > result diagnostic for empty types. This diagnostic is emitted from > > tree-cfg.cc because of a couple code paths which attempt to avoid > > copying empty types, resulting in GIMPLE that isn't using the returned > > value of a call. To fix this I've added suppress_warning in three locations > > and a corresponding check in do_warn_unused_result. > > This is OK, but I wonder about making do_warn_unused_result ignore empty > types in general; if there's no data in the type, what does it matter if > we ignore the empty box? > > > Cheers, > > Jeremy > > > > > > PR c/82134 > > > > gcc/cp/ChangeLog: > > > > * call.cc (build_call_a): Add suppress_warning > > * cp-gimplify.cc (cp_gimplify_expr): Add suppress_warning > > > > gcc/ChangeLog: > > > > * gimplify.cc (gimplify_modify_expr): Add suppress_warning > > * tree-cfg.cc (do_warn_unused_result): Check warning_suppressed_p > > > > gcc/testsuite/ChangeLog: > > > > * c-c++-common/attr-warn-unused-result-2.c: New test. > > > > Signed-off-by: Jeremy Rifkin > > --- > > gcc/cp/call.cc| 1 + > > gcc/cp/cp-gimplify.cc | 1 + > > gcc/gimplify.cc | 1 + > > .../c-c++-common/attr-warn-unused-result-2.c | 15 +++ > > gcc/tree-cfg.cc | 2 ++ > > 5 files changed, 20 insertions(+) > > create mode 100644 gcc/testsuite/c-c++-common/attr-warn-unused-result-2.c > > > > diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc > > index 2c3ef3dfc35..a70fc13c6a4 100644 > > --- a/gcc/cp/call.cc > > +++ b/gcc/cp/call.cc > > @@ -412,6 +412,7 @@ build_call_a (tree function, int n, tree *argarray) > > /* We're disconnecting the initializer from its target, > >don't create a temporary. */ > > arg = TARGET_EXPR_INITIAL (arg); > > +suppress_warning (arg, OPT_Wunused_result); > > tree t = build0 (EMPTY_CLASS_EXPR, TREE_TYPE (arg)); > > arg = build2 (COMPOUND_EXPR, TREE_TYPE (t), arg, t); > > CALL_EXPR_ARG (function, i) = arg; > > diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc > > index 0fcfa16d2c5..2a21e960994 100644 > > --- a/gcc/cp/cp-gimplify.cc > > +++ b/gcc/cp/cp-gimplify.cc > > @@ -690,6 +690,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, > > gimple_seq *post_p) > > && (REFERENCE_CLASS_P (op1) || DECL_P (op1))) > > op1 = build_fold_addr_expr (op1); > > > > +suppress_warning (op1, OPT_Wunused_result); > > gimplify_and_add (op1, pre_p); > > } > > gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, > > diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc > > index 9f9ff92d064..fa9890e7cea 100644 > > --- a/gcc/gimplify.cc > > +++ b/gcc/gimplify.cc > > @@ -7305,6 +7305,7 @@ gimplify_modify_expr (tree *expr_p, gimple_seq > > *pre_p, gimple_seq *post_p, > > && !(TREE_ADDRESSABLE (TREE_TYPE (*from_p)) > > && TREE_CODE (*from_p) == CALL_EXPR)) > > { > > + suppress_warning (*from_p, OPT_Wunused_result); > > gimplify_stmt (from_p, pre_p); > > gimplify_stmt (to_p, pre_p); > > *expr_p = NULL_TREE; > > diff --git a/gcc/testsuite/c-c++-common/attr-warn-unused-result-2.c > > b/gcc/testsuite/c-c++-common/attr-warn-unused-result-2.c > > new file mode 100644 > > index 000..09be1a933c9 > > --- /dev/null > > +++ b/gcc/testsuite/c-c++-common/attr-warn-unused-result-2.c > > @@ -0,
Re: [PATCH] c, c++: Fix unused result for empty types [PR82134]
Hi, I'm bumping this patch. Jeremy On Mon, Jun 9, 2025 at 8:00 PM Jeremy Rifkin wrote: > > Hi, > This fixes PR c/82134 which concerns gcc emitting an incorrect unused > result diagnostic for empty types. This diagnostic is emitted from > tree-cfg.cc because of a couple code paths which attempt to avoid > copying empty types, resulting in GIMPLE that isn't using the returned > value of a call. To fix this I've added suppress_warning in three locations > and a corresponding check in do_warn_unused_result. > > Cheers, > Jeremy > > > PR c/82134 > > gcc/cp/ChangeLog: > > * call.cc (build_call_a): Add suppress_warning > * cp-gimplify.cc (cp_gimplify_expr): Add suppress_warning > > gcc/ChangeLog: > > * gimplify.cc (gimplify_modify_expr): Add suppress_warning > * tree-cfg.cc (do_warn_unused_result): Check warning_suppressed_p > > gcc/testsuite/ChangeLog: > > * c-c++-common/attr-warn-unused-result-2.c: New test. > > Signed-off-by: Jeremy Rifkin > --- > gcc/cp/call.cc| 1 + > gcc/cp/cp-gimplify.cc | 1 + > gcc/gimplify.cc | 1 + > .../c-c++-common/attr-warn-unused-result-2.c | 15 +++ > gcc/tree-cfg.cc | 2 ++ > 5 files changed, 20 insertions(+) > create mode 100644 gcc/testsuite/c-c++-common/attr-warn-unused-result-2.c > > diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc > index 2c3ef3dfc35..a70fc13c6a4 100644 > --- a/gcc/cp/call.cc > +++ b/gcc/cp/call.cc > @@ -412,6 +412,7 @@ build_call_a (tree function, int n, tree *argarray) >/* We're disconnecting the initializer from its target, > don't create a temporary. */ >arg = TARGET_EXPR_INITIAL (arg); > +suppress_warning (arg, OPT_Wunused_result); > tree t = build0 (EMPTY_CLASS_EXPR, TREE_TYPE (arg)); > arg = build2 (COMPOUND_EXPR, TREE_TYPE (t), arg, t); > CALL_EXPR_ARG (function, i) = arg; > diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc > index 0fcfa16d2c5..2a21e960994 100644 > --- a/gcc/cp/cp-gimplify.cc > +++ b/gcc/cp/cp-gimplify.cc > @@ -690,6 +690,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, > gimple_seq *post_p) > && (REFERENCE_CLASS_P (op1) || DECL_P (op1))) >op1 = build_fold_addr_expr (op1); > > +suppress_warning (op1, OPT_Wunused_result); > gimplify_and_add (op1, pre_p); >} > gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, > diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc > index 9f9ff92d064..fa9890e7cea 100644 > --- a/gcc/gimplify.cc > +++ b/gcc/gimplify.cc > @@ -7305,6 +7305,7 @@ gimplify_modify_expr (tree *expr_p, gimple_seq > *pre_p, gimple_seq *post_p, >&& !(TREE_ADDRESSABLE (TREE_TYPE (*from_p)) > && TREE_CODE (*from_p) == CALL_EXPR)) > { > + suppress_warning (*from_p, OPT_Wunused_result); >gimplify_stmt (from_p, pre_p); >gimplify_stmt (to_p, pre_p); >*expr_p = NULL_TREE; > diff --git a/gcc/testsuite/c-c++-common/attr-warn-unused-result-2.c > b/gcc/testsuite/c-c++-common/attr-warn-unused-result-2.c > new file mode 100644 > index 000..09be1a933c9 > --- /dev/null > +++ b/gcc/testsuite/c-c++-common/attr-warn-unused-result-2.c > @@ -0,0 +1,15 @@ > +// PR c/82134 > +/* { dg-do compile } */ > + > +struct S {}; > + > +__attribute__((warn_unused_result)) struct S foo(); > + > +void use_s(struct S); > + > +void > +test (void) > +{ > + struct S s = foo(); /* { dg-bogus "ignoring return value of" } */ > + use_s(foo()); /* { dg-bogus "ignoring return value of" } */ > +} > diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc > index fad308e7f7b..5cd72ed1b3e 100644 > --- a/gcc/tree-cfg.cc > +++ b/gcc/tree-cfg.cc > @@ -9961,6 +9961,8 @@ do_warn_unused_result (gimple_seq seq) > break; >if (gimple_call_internal_p (g)) > break; > + if (warning_suppressed_p (g, OPT_Wunused_result)) > +break; > >/* This is a naked call, as opposed to a GIMPLE_CALL with an > LHS. All calls whose value is ignored should be > -- > 2.43.0 >