diff options
author | Arsen Arsenović <arsen@aarsen.me> | 2024-09-20 13:13:02 +0200 |
---|---|---|
committer | Arsen Arsenović <arsen@gcc.gnu.org> | 2024-09-27 13:37:37 +0200 |
commit | de03ef6337b0a368d61c74b790313b4216c7ed6e (patch) | |
tree | 5e56f3e15bde60e69338bfc637f1a42c62168b50 | |
parent | 05e4f07cad1eacf869c10622cae2a9cdee3b6a7a (diff) | |
download | gcc-de03ef6337b0a368d61c74b790313b4216c7ed6e.zip gcc-de03ef6337b0a368d61c74b790313b4216c7ed6e.tar.gz gcc-de03ef6337b0a368d61c74b790313b4216c7ed6e.tar.bz2 |
c++: simplify handling implicit INDIRECT_REF and co_await in convert_to_void
convert_to_void has, so far, when converting a co_await expression to
void altered the await_resume expression of a co_await so that it is
also converted to void. This meant that the type of the await_resume
expression, which is also supposed to be the type of the whole co_await
expression, was not the same as the type of the CO_AWAIT_EXPR tree.
While this has not caused problems so far, it is unexpected, I think.
Also, convert_to_void had a special case when an INDIRECT_REF wrapped a
CALL_EXPR. In this case, we also diagnosed maybe_warn_nodiscard. This
was a duplication of logic related to converting call expressions to
void.
Instead, we can generalize a bit, and rather discard the expression that
was implicitly dereferenced instead.
This patch changes the diagnostic of:
void f(struct S* x) { static_cast<volatile S&>(*x); }
... from:
warning: indirection will not access object of incomplete type
'volatile S' in statement
... to:
warning: implicit dereference will not access object of type
‘volatile S’ in statement
... but should have no impact in other cases.
gcc/cp/ChangeLog:
* coroutines.cc (co_await_get_resume_call): Return a tree
directly, rather than a tree pointer.
* cp-tree.h (co_await_get_resume_call): Adjust signature
accordingly.
* cvt.cc (convert_to_void): Do not alter CO_AWAIT_EXPRs when
discarding them. Simplify handling implicit INDIRECT_REFs.
gcc/testsuite/ChangeLog:
* g++.dg/coroutines/nodiscard-1.C: New test.
-rw-r--r-- | gcc/cp/coroutines.cc | 4 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 2 | ||||
-rw-r--r-- | gcc/cp/cvt.cc | 102 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/coroutines/nodiscard-1.C | 77 |
4 files changed, 132 insertions, 53 deletions
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 50904e0..8e4c55a 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -730,14 +730,14 @@ coro_get_destroy_function (tree decl) /* Given a CO_AWAIT_EXPR AWAIT_EXPR, return its resume call. */ -tree* +tree co_await_get_resume_call (tree await_expr) { gcc_checking_assert (TREE_CODE (await_expr) == CO_AWAIT_EXPR); tree vec = TREE_OPERAND (await_expr, 3); if (!vec) return nullptr; - return &TREE_VEC_ELT (vec, 2); + return TREE_VEC_ELT (vec, 2); } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7c438ec..39c065e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8782,7 +8782,7 @@ extern tree coro_get_actor_function (tree); extern tree coro_get_destroy_function (tree); extern tree coro_get_ramp_function (tree); -extern tree* co_await_get_resume_call (tree await_expr); +extern tree co_await_get_resume_call (tree await_expr); /* contracts.cc */ diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc index df02b8f..526937d 100644 --- a/gcc/cp/cvt.cc +++ b/gcc/cp/cvt.cc @@ -1272,88 +1272,96 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain) complete_type (type); int is_complete = COMPLETE_TYPE_P (type); - /* Can't load the value if we don't know the type. */ - if (is_volatile && !is_complete) + /* Don't load the value if this is an implicit dereference, or if + the type needs to be handled by ctors/dtors. */ + if (is_reference) { - if (complain & tf_warning) + if (is_volatile && (complain & tf_warning) + /* A co_await expression, in its await_resume expression, also + contains an implicit dereference. As a result, we don't + need to warn about them here. */ + && TREE_CODE (TREE_OPERAND (expr, 0)) != CO_AWAIT_EXPR) switch (implicit) { case ICV_CAST: warning_at (loc, 0, "conversion to void will not access " - "object of incomplete type %qT", type); + "object of type %qT", type); break; case ICV_SECOND_OF_COND: - warning_at (loc, 0, "indirection will not access object of " - "incomplete type %qT in second operand " - "of conditional expression", type); + warning_at (loc, 0, "implicit dereference will not access " + "object of type %qT in second operand of " + "conditional expression", type); break; case ICV_THIRD_OF_COND: - warning_at (loc, 0, "indirection will not access object of " - "incomplete type %qT in third operand " - "of conditional expression", type); + warning_at (loc, 0, "implicit dereference will not access " + "object of type %qT in third operand of " + "conditional expression", type); break; case ICV_RIGHT_OF_COMMA: - warning_at (loc, 0, "indirection will not access object of " - "incomplete type %qT in right operand of " + warning_at (loc, 0, "implicit dereference will not access " + "object of type %qT in right operand of " "comma operator", type); break; case ICV_LEFT_OF_COMMA: - warning_at (loc, 0, "indirection will not access object of " - "incomplete type %qT in left operand of " - "comma operator", type); + warning_at (loc, 0, "implicit dereference will not access " + "object of type %qT in left operand of comma " + "operator", type); break; case ICV_STATEMENT: - warning_at (loc, 0, "indirection will not access object of " - "incomplete type %qT in statement", type); + warning_at (loc, 0, "implicit dereference will not access " + "object of type %qT in statement", type); break; case ICV_THIRD_IN_FOR: - warning_at (loc, 0, "indirection will not access object of " - "incomplete type %qT in for increment " - "expression", type); + warning_at (loc, 0, "implicit dereference will not access " + "object of type %qT in for increment expression", + type); break; default: gcc_unreachable (); } + + /* Since this was an implicit dereference, we should also act as if + it was never there. */ + return convert_to_void (TREE_OPERAND (expr, 0), implicit, complain); } - /* Don't load the value if this is an implicit dereference, or if - the type needs to be handled by ctors/dtors. */ - else if (is_volatile && is_reference) + /* Can't load the value if we don't know the type. */ + else if (is_volatile && !is_complete) { if (complain & tf_warning) switch (implicit) { case ICV_CAST: warning_at (loc, 0, "conversion to void will not access " - "object of type %qT", type); + "object of incomplete type %qT", type); break; case ICV_SECOND_OF_COND: - warning_at (loc, 0, "implicit dereference will not access " - "object of type %qT in second operand of " - "conditional expression", type); + warning_at (loc, 0, "indirection will not access object of " + "incomplete type %qT in second operand " + "of conditional expression", type); break; case ICV_THIRD_OF_COND: - warning_at (loc, 0, "implicit dereference will not access " - "object of type %qT in third operand of " - "conditional expression", type); + warning_at (loc, 0, "indirection will not access object of " + "incomplete type %qT in third operand " + "of conditional expression", type); break; case ICV_RIGHT_OF_COMMA: - warning_at (loc, 0, "implicit dereference will not access " - "object of type %qT in right operand of " + warning_at (loc, 0, "indirection will not access object of " + "incomplete type %qT in right operand of " "comma operator", type); break; case ICV_LEFT_OF_COMMA: - warning_at (loc, 0, "implicit dereference will not access " - "object of type %qT in left operand of comma " - "operator", type); + warning_at (loc, 0, "indirection will not access object of " + "incomplete type %qT in left operand of " + "comma operator", type); break; case ICV_STATEMENT: - warning_at (loc, 0, "implicit dereference will not access " - "object of type %qT in statement", type); + warning_at (loc, 0, "indirection will not access object of " + "incomplete type %qT in statement", type); break; case ICV_THIRD_IN_FOR: - warning_at (loc, 0, "implicit dereference will not access " - "object of type %qT in for increment expression", - type); + warning_at (loc, 0, "indirection will not access object of " + "incomplete type %qT in for increment " + "expression", type); break; default: gcc_unreachable (); @@ -1403,7 +1411,7 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain) gcc_unreachable (); } } - if (is_reference || !is_volatile || !is_complete || TREE_ADDRESSABLE (type)) + if (!is_volatile || !is_complete || TREE_ADDRESSABLE (type)) { /* Emit a warning (if enabled) when the "effect-less" INDIRECT_REF operation is stripped off. Note that we don't warn about @@ -1418,9 +1426,6 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain) && !is_reference) warning_at (loc, OPT_Wunused_value, "value computed is not used"); expr = TREE_OPERAND (expr, 0); - if (TREE_CODE (expr) == CALL_EXPR - && (complain & tf_warning)) - maybe_warn_nodiscard (expr, implicit); } break; @@ -1503,12 +1508,9 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain) break; case CO_AWAIT_EXPR: - { - auto awr = co_await_get_resume_call (expr); - if (awr && *awr) - *awr = convert_to_void (*awr, implicit, complain); - break; - } + if (auto awr = co_await_get_resume_call (expr)) + convert_to_void (awr, implicit, complain); + break; default:; } diff --git a/gcc/testsuite/g++.dg/coroutines/nodiscard-1.C b/gcc/testsuite/g++.dg/coroutines/nodiscard-1.C new file mode 100644 index 0000000..b4c6729 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/nodiscard-1.C @@ -0,0 +1,77 @@ +#include <coroutine> +/* Make sure that we correctly warn for unused co_await results. */ + +struct task +{ + struct promise_type + { + std::suspend_never initial_suspend () noexcept; + std::suspend_never final_suspend () noexcept; + void return_void (); + void unhandled_exception (); + task get_return_object (); + }; +}; + +template<typename T> +struct nodiscardable : std::suspend_never +{ [[nodiscard]] T await_resume (); }; + +template<typename T> +struct discardable : std::suspend_never +{ T await_resume (); }; + +task +thing () +{ + co_await nodiscardable<int&>{}; /* { dg-warning "attribute 'nodiscard'" } */ + co_await nodiscardable<int>{}; /* { dg-warning "attribute 'nodiscard'" } */ + + (void) co_await nodiscardable<int&>{}; + (void) co_await nodiscardable<int>{}; + + co_await discardable<int&>{}; + co_await discardable<volatile int&>{}; + /* { dg-warning "implicit dereference will not access" "" { target *-*-* } {.-1} } */ +} + +template<typename> +task +other_thing () +{ + co_await nodiscardable<int&>{}; /* { dg-warning "attribute 'nodiscard'" } */ + co_await nodiscardable<int>{}; /* { dg-warning "attribute 'nodiscard'" } */ + + (void) co_await nodiscardable<int&>{}; + (void) co_await nodiscardable<int>{}; + + co_await discardable<int&>{}; + co_await discardable<volatile int&>{}; + /* { dg-warning "implicit dereference will not access" "" { target *-*-* } {.-1} } */ +} + +void +other_thing_caller () +{ + other_thing <int> (); +} + +task +yet_another_thing (auto) +{ + co_await nodiscardable<int&>{}; /* { dg-warning "attribute 'nodiscard'" } */ + co_await nodiscardable<int>{}; /* { dg-warning "attribute 'nodiscard'" } */ + + (void) co_await nodiscardable<int&>{}; + (void) co_await nodiscardable<int>{}; + + co_await discardable<int&>{}; + co_await discardable<volatile int&>{}; + /* { dg-warning "implicit dereference will not access" "" { target *-*-* } {.-1} } */ +} + +void +yet_another_thing_caller () +{ + yet_another_thing (1); +} |