aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorArsen Arsenović <arsen@aarsen.me>2024-09-20 13:13:02 +0200
committerArsen Arsenović <arsen@gcc.gnu.org>2024-09-27 13:37:37 +0200
commitde03ef6337b0a368d61c74b790313b4216c7ed6e (patch)
tree5e56f3e15bde60e69338bfc637f1a42c62168b50 /gcc
parent05e4f07cad1eacf869c10622cae2a9cdee3b6a7a (diff)
downloadgcc-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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/coroutines.cc4
-rw-r--r--gcc/cp/cp-tree.h2
-rw-r--r--gcc/cp/cvt.cc102
-rw-r--r--gcc/testsuite/g++.dg/coroutines/nodiscard-1.C77
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);
+}